Repository navigation
Releases
v0.48.1
A release installed from your machine with one command, and CoreX's abilities visible to MCP agents (spec 123, User Stories 1 and 4; DECISIONS #500, #508, #512, #513).
Read Client impact before updating. Nothing changes on a live site until its wp-config.php defines COREX_ALLOW_RELEASE_PUSH, or until the MCP Adapter plugin is installed. This release itself is installed from the Releases screen, as before: it is the first one whose routes accept the command.
Added
- A release can be installed from your machine with one command, with no browser (spec 123, User Story 4; DECISIONS #512, #513).
npm run release:push -- --client=<name>builds the client's package withbuild:dist --zip, sends it to the site in parts, installs it through the Releases routes with the Releases screen's own client code, then checks that the site runs the new version and its home page answers.--package=<file>sends a package already built. On a failure after the release was put in place it prints the recovery link and the way back, and--resumegoes on with an installation a run did not finish, carrying the installation's key it kept. Guide:docs/en/05-deployment/releases-from-your-machine.md.- Every Releases route now accepts a request signed in with an Application Password in place of the screen's nonce, only on a site whose
wp-config.phpdefinesCOREX_ALLOW_RELEASE_PUSHastrue, only over HTTPS (or on alocalsite), and only for an account that may install releases. Without the constant every such request is refused withpush_off. A request signed in by cookie still needs the nonce. - The release history and the activity log name the Application Password a release was installed with.
- This supersedes DECISIONS #502 (an Application Password on the three upload routes only).
- Every Releases route now accepts a request signed in with an Application Password in place of the screen's nonce, only on a site whose
Changed
- CoreX's abilities are visible to MCP agents (spec 123, User Story 1; DECISIONS #500, #508).
corex/site-infoandcorex/list-blocksnow setmeta.mcp.public, so the official MCP Adapter's default server lists them. Before this, an agent connected to a CoreX site saw only WordPress's owncore/*abilities, and asking forcorex/site-infoanswered "not found".- Both stay on the Abilities REST routes.
- Both are marked read-only and safe to repeat.
- Both still need
edit_posts, becausecorex/site-infocarries the CoreX version, which spec 111 keeps out of every public page.
Security
- Ten dependency advisories published since 2026-10-23 (twelve findings) are closed with patched releases. They failed "Validate dependency advisories" on every pull request opened since. Each patched release sits inside the range its parent already accepts, and the lockfiles change only those entries:
- root:
body-parser1.20.6 to 1.20.9 (and 2.3.0 to 2.4.0 underwebpack-dev-server, withcontent-type2.1.0),fast-uri3.1.8 to 3.1.9,serialize-javascript7.0.7 to 7.1.4,zod4.6.5 to 4.6.7; - docs site:
undici8.10.2 to 8.12.3,zod4.5.4 to 4.6.7.
- root:
- The
bracesexception (GHSA-vfj7-8cjw-p6xm) is removed: GitHub withdrew the advisory on 2026-10-23, and the policy refuses an exception that matches no advisory. No exception is added.
Client impact
- Installing releases with one command (Muva, Perego, any client site). Nothing changes on a site until its
wp-config.phpsaysdefine( 'COREX_ALLOW_RELEASE_PUSH', true );; until then the Releases routes refuse every Application Password, and the Releases screen works as before. To use it:- install this release from the Releases screen, as now: the release running on a site decides who may use its routes, and older ones accept only the screen;
- add the line to the site's
wp-config.php(besideCOREX_ALLOW_RELEASE_INSTALLon a host that setsDISALLOW_FILE_MODS); - make an Application Password (Users > Profile) for an account that may install releases, ideally one kept for this;
- put
{"site", "user", "application_password"}in~/.corex/release-push/<client>.json, outside the repository; - run
npm run release:push -- --client=<client> [--with-plugin=<folder>]from the client repository, after any build step of the client's own (Muva runssites/muva/deploy/package.mjs --keepfirst, or wires both into one script of its own).
- Muva and Perego: nothing changes until the MCP Adapter plugin is installed on the site. Then any signed-in agent sees
corex/site-infoandcorex/list-blockslisted (the adapter's discovery checks no permission), and an author or above can run them. The dependency updates are lockfile entries for build, test and docs tooling; no CoreX plugin or theme source imports any of them. - Mizzey is pinned to v0.42.0 and is not affected until it moves.
v0.48.0
The rest of the CoreX revamp's stage 0 and its first quality release: mail stays where it should (spec 113, R0.2, DECISIONS #381 to #385), screens that tell the truth (spec 114, R0.3, #390 to
#398), kit and public page safety (spec 115, R0.4, #400 to #407), and quality checks on every
release (spec 116, R1.1, #410 to #419).
Read Client impact before updating. Four things can change on a live site:
- A site whose
.envsaysAPP_ENV=local,developmentorstaging, or whose operations mode is Development or Staging, now keeps its mail in Email Studio instead of sending it. Check both before updating. - Kit pages that still reference the stats or testimonial patterns lose those two sections for visitors until someone edits them, and pattern buttons with no Brand action link or contact page are hidden. Perego runs the Company kit: check its pages.
- The bookings, careers and newsletter routes now judge a reCAPTCHA v3 token by its action, hostname and score: a site's own form must request its token under the route's action.
- The Overview, Security Center and Insights now say what is true, so some rows that read "Done" or "Hidden" may now read "Not set", "Off" or "Not configured".
Added
- Quality checks on every release (spec 116, R1.1 of the CoreX revamp). A new CI job, Quality checks, opens every CoreX admin screen and tab and every theme template in eight cells (375 and 1280px, light and dark, left to right and right to left) on a WordPress with the Company kit applied. It checks for sideways scroll, WCAG 2.2 AA (axe-core, contrast and target size included) and raw developer keys. At phone width it checks tables, 44px controls, the rail and text at 200%. It also checks focus and Escape, reduced motion, the empty, loading, failed and refused states of every screen, untranslated words (a pseudo-locale run) and a front-end budget: layout shift, image sizes, lazy images, CoreX bytes per page, and block assets only where the block is. What
mainshowed when the checks were written is intests/e2e/quality/known-failures.json, each entry with the story that fixes it. A new defect fails the job.node scripts/quality-known-failures.mjsprints the list. - The admin's colour tokens are checked for contrast, dark and light, before any browser opens (
ContrastMatrixTest). - A PHP translation lint (
php scripts/i18n-lint.php), the product completion audit (npm run audit:completion) and the admin read and form budgets (composer test:performance) run in CI. The translation templatecorex.potis generated on every pull request and attached to every published release. - A client merge check (
scripts/client-merge-check.mjs) merges a release candidate into a throwaway clone of a client repository. It names a conflict in a file the client records as a local edit, runs the client's suites and writes a report for the release record. CI proves it on a generated client site. wp eval-file scripts/clean-test-residue.phplists and, when told to, removes the submissions test runs left on a development site. It refuses a production site.
Changed
- One setting decides whether a site is a development site (spec 113).
APP_ENVin.env, a value the network locks or thecorex_app_envoption decides first, and locks the operations mode (the Operations screen says what locks it and offers that environment's mode, Coming soon and Maintenance); then the operations mode; then WordPress's environment type, wherelocalnow counts as Development. A site in Coming soon or Maintenance stays closed to visitors whateverAPP_ENVsays. Email Studio, Insights and the Settings diagnostics show the same answer and where it comes from. - Mail stays on a development or staging site (spec 113). Every email, from every CoreX path, from WordPress and from other plugins, is captured into
Email Studio → Delivery logs, named by what sent it ("Form notification", "Newsletter: new post", "WordPress: password reset", "Other: wp_mail"), and nobody receives it. Staging sends for real once a provider is set and live delivery is on. A switch on the Email Studio overview, Capture only CoreX mail, lets WordPress's and other plugins' mail through. Without CoreX Mail active, such an email is not sent and is recorded in the activity log. A production site, and a site in Coming soon or Maintenance with no development or stagingAPP_ENV, sends exactly as before. - A flow's "Run marked test" holds its emails on every site (spec 113), production included: the result lists each with a link to it in Email Studio, and the Test tab says so before the button is pressed.
- Email Studio says on every tab what happens to mail on this site: delivered for real, captured, or blocked, with live delivery, the provider, what decided, and any kind of email that does not follow it.
- Email Studio's log shows the newest mail first however many emails are stored, the overview counts say they are of the last 100 emails, and captured and held emails are deleted after 30 days (they were kept forever).
- The Overview shows only true states (#390). Brand reads "Done" only with a company name and a logo, otherwise "Not set" with a link to Brand settings. Insights / PageSpeed reads "Connected" only with a saved key whose last run completed, "Key saved, not checked yet", "Keyless (shared quota)", or "Error" with the reason after a failed run. Captcha reads "Not configured" for None or Honeypot and when the captcha add-on is off. Spam protection says "Honeypot only" or "Honeypot and ". Login protection reads the Security Center, and hardening has a row of its own. A fact that cannot be read says "Could not check".
- "Default login endpoints: Hidden" only when they are (#391). The Security Center row reads "Reachable" while login protection or hiding is off, and "Recovery active: the default login is reachable" while
COREX_LOGIN_UNGUARDis set, with how to end recovery. The login guard, the Security Center and the Overview ask one rule. - A PageSpeed run that could not run shows an error, never a grade (#392): "Could not run", the reason and Retry, with no score. Failed runs stored by earlier releases as 50/D are shown as failures with their message; none is deleted.
- Insights security events are complete (#393). Operations-mode changes, refused visits to CoreX screens (one event per counted entry), sign-in lockouts and access-request decisions are in the activity log, and the card shows the newest five of them whatever else happened, and from when it has records. Events from before the update stay in their own logs.
- The Add-ons screen reports what really happened (#395). A failed activation shows WordPress's reason, leaves the add-on off, writes no feature flag and shows no kit prompt. An add-on active for the network ("Managed by the network administrator") or installed as must-use ("Must-use: always on") has a switch that cannot be used. Each enable and disable is in the activity log.
- The login screen shows no single sign-on option (#396), whatever the stored setting says, and Settings → Brand no longer offers "Enable SSO login section". The stored value is left in place.
- Blog Pro says plainly that it does not count readers yet (#397). Without reading data it shows one line instead of the reading-signals panel and the period line, and the Sharing card is gone.
- Dependency advisories of 2026-10-22: the docs site takes astro 7.3.3 (GHSA-mpr7-6m5w-76rw, low), and the
sprintf-jsexception is removed because GitHub withdrew its advisory (GHSA-hp3w-g68c-fv3c). Development dependencies only; no package ships them. - A browser test run cleans up after itself. It prints the site it will write to, refuses one in Production mode served from a real host name, removes the submissions it made and fails if it left any without a test's marker. The test fixture plug-ins say "Test fixture" where a person sees them.
COREX_BASE_URLhas no default any more:npm run test:e2eandnpm run test:qualityrefuse to start until it names the site to test (it used to fall back tohttp://corex.local). - A Client impact section names each running client site, Muva, Perego and Mizzey, or says that no client site is affected. The changelog test enforces it from this release on.
- The completion audit's "coming soon" rule no longer matches the name of the Coming soon mode, only a promise ("(coming soon)", "is coming soon"), and the audit reads every folder CoreX ships instead of a list that left most add-ons out.
- In CI, a failing linter no longer stops the audit, the unit tests and Jest in the same job, so one run reports every failure.
- A reset gives back the pages the owner had (DECISIONS #400). - Applying a kit now records each page it replaces or adopts (title, content, template, status) and the site's front-page settings before it changes them. -
wp corex resetrestores those pages with the same ID and address instead of deleting them, and puts the front page back. - A page replaced before this release, with nothing recorded, is kept as it is and listed as "kept: no earlier version recorded". ---dry-runlists each page as created (will be removed), replaced (will be restored) or adopted (will be emptied). - The setup wizard says what it records (DECISIONS #401). It no longer says it backs the site up. The Backup step lists the pages the plan will record, recommends a full backup with the host or a backup plugin, and keeps Apply off until the person confirms they have one.
- Shipped patterns make no claims for the site (DECISIONS #402, #403). - The stats, testimonial and logo-cloud patterns are marked as samples. A visitor sees nothing of them until someone changes them in the editor; an editor sees them labelled "Sample: replace before publishing". - The theme's header, footer and mega...
v0.47.0
Access and logs (spec 112, the first release of the CoreX revamp), the generator tag (spec 111) and backslashes kept in submissions on a site with ACF active.
Read Client impact before updating. Access granted by approval before this release stays in effect with no expiry; review it in CoreX → Access & Abilities. In Maintenance, a site's CoreX forms now answer 503 and store nothing. The foundation schema goes from 3 to 4: five nullable columns on the access requests table, added by wp corex migrate or by the first admin page or WP-Cron run after the update.
Changed
- Access requests and grants (spec 112). Abilities that control the whole site (CoreX admin, access, operations and security, releases, dangerous actions) are granted through the role matrix only: a request for one is refused, and their screens' access-denied page says how access is given instead of offering a form. Approving a request now shows each ability it grants with its risk and the requester's reason, and needs a note, an expiry of 7, 30 or 90 days and, for a dangerous ability, its key typed. Access & Abilities lists the access granted by approval, with Revoke; once a day CoreX ends the grants whose expiry has passed and tells the person and the approver. Grants approved before this release are listed as having no expiry, stay in effect, and can now be reviewed and revoked: worth a look, because CoreX screens will check their own abilities in a later release.
- The access audit log counts refusals: one line per person, screen and hour, with how many times and from when to when.
- Maintenance closes public submissions (spec 112). In Maintenance, CoreX forms, flows, newsletter sign-ups, booking requests, job applications and account registration answer 503 and store and mail nothing; sign-in and password reset stay open, a signed-in administrator can still submit, and Coming soon is unchanged. A REST route of a site's own closes with them when it declares
Corex\Http\PublicSubmission::MARKER => true. - Login recovery without a command line. The Recovery panel gives the
COREX_LOGIN_UNGUARDline to add towp-config.phpthrough a host's file manager, as well as the command, both ready to copy; the Security Center says while recovery is on. - Blog Pro follows WordPress's permissions for each post and comment: it opens for anyone who can edit posts, a post's figures and moves need permission to edit it (and to publish it, to publish or schedule), approving, spamming, trashing and replying to comments need comment moderation rights, and a refusal says what is not allowed.
- Security records on the Data screen (role ability grants, access requests, sign-in attempts) need the ability of the screen they belong to as well as "Manage data"; an export of several models leaves such a model out and says why.
- An email resent from the inbox goes to the people it was sent to. Flow emails record who they were sent to; a resend goes to them, and the drawer names each email, says who a resend went to, and says why an email cannot be resent.
Added
- Every front-end page says the site runs CoreX (spec 111). The page head carries
<meta name="generator" content="CoreX" />beside WordPress's own, so technology scanners such as Wappalyzer can recognise a CoreX site. It names no version. It is left off the Coming soon page a visitor sees, andadd_filter('corex_generator_tag', '__return_false')leaves it off every page of a site. The detection rule for the scanners' lists is inspecs/111-generator-tag/contracts/detection-rule.md.
Fixed
- A site with ACF active keeps backslashes in what is submitted (DECISIONS #375). The ACF field driver handed ACF the value as it was, and ACF stores a post's value through
update_metadata(), which takes one level of slashes off. A visitor who wroteC:\offers\newwas read in the inbox asC:offersnew. The same was fixed for sites without ACF in v0.46.0.
Security
- Dependency advisories of 2026-10-20. Five advisories published that evening failed the advisory check on every pull request. All five are closed by patched releases in the ranges the packages that use them already accept, so no exception is added:
launch-editor2.14.2 (three advisories; used by the webpack dev server behindnpm start),markdown-it14.3.3 (two; installed formarkdownlint-cli, with the root override's floor raised from 14.3.2) andvite8.1.6 indocs-app(the same threelaunch-editoradvisories, which vite bundles). All three are build and local development tooling. The built plugin assets (169 files) and the docs site built without the generated class reference (146 files) are byte-identical before and after.
Client impact
- Review the access granted by approval (spec 112) in CoreX → Access & Abilities: grants approved before this release are listed with no expiry and stay in effect until revoked.
- In Maintenance, a client site's CoreX forms answer 503 and store nothing; Coming soon is unchanged.
- Editors and writers can open Blog Pro and act on what WordPress lets them; administrators see no change.
- A person given "Manage data" who is not an administrator no longer sees the three security models on the Data screen.
- A site that implements its own
SubmissionEmailGatewaykeeps working unchanged; a resend through it goes to each recipient in turn. A site that builds its ownManagedTablekeeps working; it can addownerAbility:. A client repository that carries copies of CoreX's own tests takes the updatedtests/Unit/Access/AccessServiceTest.phpwith this release. - A site with ACF active keeps backslashes in submissions from the update on. Nothing to do. Submissions stored before it are not repaired: what was dropped is not in the database.
- Every page of a client site gains one line in its head,
<meta name="generator" content="CoreX" />. Nothing to do. A client that does not want its pages to name CoreX addsadd_filter('corex_generator_tag', '__return_false');to its own plugin or theme, and clears its page cache.
v0.46.1
CoreX → Releases on a shared host, after Perego's second installation from it on 2026-10-18 ended with the site held in maintenance for ten minutes and the release not in place.
A site that installs from CoreX → Releases should take this release, and read Client impact first. The installation that brings it is still run by v0.46.0's code, so on a shared host the contents of wp-content/corex-releases/previous/ are deleted in the host's file manager before it is installed.
What changed. The request that puts a release in place no longer deletes the release kept from the installation before while visitors are held off. An installation's key also travels in the address, so it gets through WordPress's maintenance answer on a host that drops request headers, and the screen keeps asking for as long as that answer can last. An installation that stopped before any folder moved can be given up from the screen, and what an installation left behind is named and removed when asked. A package that would put a third-party plugin or theme back to an older version than the site has says so, and installs only when that is confirmed.
Rebuild plugins/corex-config after merging: the admin bundle changed.
Added
- CoreX → Releases says when a package would put a plugin or theme back to an older version than the site has, and installs it only when that is confirmed (spec 107, FR-029; DECISIONS #371). Perego's package of 2026-10-18 held six third-party plugins older than the copies updated in the site's admin since it was built; installing it would have put all six back without a word. The statement names each with the site's version and the package's, before the version is typed, and the confirmation asks for a box to be ticked, which the site checks as well. CoreX's own folders are left to the older-release question.
Fixed
- The request that puts a release in place no longer deletes the release kept from the installation before (spec 107, FR-024b; DECISIONS #369). A client site's second installation from CoreX → Releases on its shared host (Perego, LiteSpeed) ended with "The site did not answer after 6 tries", ten minutes of maintenance and the release not in place; its first, with nothing kept yet, had finished. Deleting that site's kept release took 11.8 s on a development machine, with visitors held off. It is now set aside by one rename and deleted a few seconds at a time when Releases is opened.
- An installation gets through WordPress's maintenance answer on a host that does not hand PHP its request headers (FR-024a, FR-025). Reproduced on a copy of a site with the key's header dropped: the same six failed tries. The installation's key now goes in the address as well as the header, the maintenance file looks for it in the header, in the headers as the web server holds them and in the address, and the screen goes on asking for as long as WordPress's maintenance can last, saying that it is waiting. An installation's record says where its key was found (
key_from). - An installation that stopped as its release was being put in place, before any folder moved, can be given up from CoreX → Releases (FR-022a; DECISIONS #370). Perego's screen offered only "Go on with it" there. Giving it up lets visitors in and removes its recovery plugin and the unpacked release; once a folder has moved it is refused, as before.
- CoreX → Releases names what an installation left when none is in progress, and removes it when asked (FR-022b): an unpacked release, a recovery plugin no installation holds the key of, a kept release with no journal. Perego's screen said "No installation is in progress" beside them, and the owner removed them in the host's file manager. New route:
POST corex/v1/releases/leftovers/remove.
Client impact
- The installation that brings this release is run by the one it replaces, and so deletes the kept release while visitors are held off. Before installing it on a shared host, delete the contents of
wp-content/corex-releases/previous/in the host's file manager (keep the folder): it is only the way back to the release before the running one. If it still ends with "The site did not answer", wait ten minutes and open CoreX → Releases. wp-content/corex-releases/discarded/is new. It holds the release before the kept one until Releases has been opened a few times, and is closed to the web server like the rest ofcorex-releases/. Nothing to do.- A package that carries third-party plugins (
--with-plugin) may now ask for one more confirmation. Where a plugin was updated in the site's admin after the package was built, Releases lists it with both versions and asks for a box to be ticked before it installs. To keep the site's newer copy, build the package again from the plugin folder the site runs now. The screen and the site's check come with the release that brings them, so the installation of this release itself is not yet asked.
CoreX v0.46.0
Everything merged since v0.45.2: two days of fixes found by using CoreX on the first client sites, the rest of the reply email's sender, and a boot that asks the database less.
A site with a form that has a file field should take this release. A form's file field is answered by the file the request carried and by nothing in its text; see Security, and the first entries of Client impact for what a site looks at in what it has stored.
Replies. A site names who its replies are from. A reply is kept as a draft, starts with a subject, is sent in the conversation the person already has or as a new email, and can be sent again when it did not go. An email is drawn, and worded, in the site's language, whoever's request sends it.
The account block. A forgotten password is reset on the account page. The block says what happened under the button that was pressed, says so when a request gets no answer, names the session in use, and its fields tell the browser what they are for.
Forms and the inbox. A form built in Forms & Flows is guarded by its trap field and the site's challenge. A form defined in code raises a notification. What a visitor writes is kept with its backslashes. On a site without pretty permalinks the inbox and seven other admin requests are answered.
Speed. CoreX's boot asks the database for nothing it does not need on a front-end request: a setting with no override costs no query, three options read on every request are stored loaded, and the schema check takes its lock only when a site is behind.
Rebuild plugins/corex-config after merging: the admin bundle changed. Read Client impact before updating a site that has code of its own against CoreX's classes or routes; it is long because the list of small changes is long, and most entries end "nothing to do".
Added
- A site names who its replies are from (spec 106, slice 5). Three settings under CoreX → Settings → Mail: Reply sender name, Reply sender address and Replies are answered to. A reply from the Submissions inbox, and one sent again, leaves from them; left blank, each falls back to the site's general sender as before. The Mail settings warn when the reply address is on another domain than the site's, as they do for the general one (DECISIONS #357).
- The page that shows a new preview link has a button that copies it (spec 101, FR-011a; the owner's ask). The link is in a field of its own, labelled, with Copy link beside it: one press puts the whole link on the clipboard and the page says "Copied.", to a screen reader as well. With scripts off there is no button and the link is copied from the field by hand. On a site not served over HTTPS, where a browser gives a page no clipboard, the button copies by selecting the field. The link is still shown once and kept nowhere (DECISIONS #327).
- A reply that was begun and not sent is kept as a draft (spec 106, slice 3). It is written down when writing pauses, and is in the box again the next time that person opens that submission, on any machine; nobody else is shown it. Sending the reply ends it; Discard draft removes it; a reply that could not be sent stays a draft. It is kept with the submission, so it goes to the trash with it and is removed when the submission is deleted or anonymized (DECISIONS #320).
- A reply that did not go can be sent again (spec 106, slice 5). A reply listed as "Not sent" has a Send again button, for anybody who may answer the submission. It sends the reply as it was written and adds what happened to that reply, which then says how many times sending it was tried. Two people pressing at once send it once: the reply is written down as being sent before the email is handed over (DECISIONS #328).
- A reply starts with a subject (spec 106, slice 9): "Re: " and the name of the form the person filled in, to keep or to change. A form defined in code is named as the inbox's own filter names it. The subject started empty and had to be written each time. A subject nobody wrote is not kept as a draft, and the box goes back to it when a reply has gone (DECISIONS #323).
- A reply is sent in the conversation the person already has, or as a new email (spec 106, slice 10). Where CoreX has a record of an email it sent the person for that submission (the confirmation, or an earlier reply), the reply box offers both, with the conversation chosen and the subject that answers it. The reply then names the email it answers, which is what a mail program reads to put it under that one. Each reply is listed with the way it went, and the preview says which it will be. Where there is no earlier email on record the reply is a new email, and the box says so. A draft keeps the way it was to be sent. Emails sent before this release cannot be continued: they left under an id nothing kept (DECISIONS #325).
- An email CoreX's mail engine sends is sent under an id CoreX chose, made of the site's host, so that a later email can say it answers it: an email Email Studio sends, and one a site sends through
Corex\Mail\Mailer. Not yet checked through a sending service that may write its own id, such as the Gmail connection of an SMTP plugin: there a reply would arrive and stand alone.
Changed
- An admin page, an
admin-ajax.phpcall and a cron run no longer write to the options table to check the schema. The check that brings a site's CoreX tables up to date took its lock before it knew whether there was anything to do: twelve statements a request, four of them writes, on every admin and cron request of a site that needed nothing, and an admin screen left open asksadmin-ajax.phpon a timer. It now reads the version of every component in one statement, and takes the lock only when one of them is behind. Measured on a development install: such a request's boot went from 11.1 ms to 7.4 ms and from 23 statements to 12. A site that is behind is brought up to date as before, under the lock, and announced once (DECISIONS #360). - A setting with no override costs no query, and an override is an option WordPress loads with the site's options (spec 001, FR-011a). On a site with no persistent object cache, CoreX's boot asked the database for eleven options that were not there, on every request: a third of a fresh site's front page. The config engine now looks for a setting's override among the options WordPress has already loaded, and so does the read of an add-on's feature flag, which leaves one of the eleven (the login protection settings, which are not a setting's override). The front page of a fresh install runs 23 queries where it ran 33. An override saved by the Settings screen, by
update_option()or bywp option updateis read as before, and so is one apre_option_filter answers. An override stored with autoload off is no longer read;wp option set-autoload <name> onmakes it one again, andwp option list --search='corex_*' --autoload=offlists what a site has stored that way, which on an install nobody has changed by hand is only CoreX's own records (DECISIONS #361). - The standard email's header is part of the card, and a logo of any shape fits it (spec 106, slice 8). The site's logo, or its name, is now the first band of the card that holds the message, under the brand's edge. It stood above the card, on the canvas, limited to 180 pixels of width and nothing of height: a square logo was drawn 180 by 180 over a narrow message. A logo from the site's library is now written at the size that fits inside 180 by 48 pixels, as the image's own width and height, which is what Outlook on Windows reads. A square mark has the site's name beside it as text, so the email still says who it is from where images are not shown; a logo that is the name written out stands alone. A vector logo is passed over, since Gmail and Outlook draw nothing for one.
wp corex make:email-designwrites the same header (DECISIONS #322). - The list of open access requests is answered to the people who decide them (spec 079, FR-011a).
GET corex/v1/access/requestsneeds a REST nonce andmanage_options, which is what the Access & Abilities screen and the decision route need. The route's two methods were registered together under the check that suits asking for access; each now has its own. Asking for access (POSTon the same route) is open to anybody signed in, as it was, and the screen shows its queue as it did (DECISIONS #346). - Three options CoreX reads on every request cost no query (spec 001, FR-011b). The login protection settings, the operations mode and the version of the Email Studio's installed defaults were each saved with autoload off and read on every request: one query each, stored or not, on a site with no persistent object cache. They are now stored where WordPress loads them with the site's options. On the first cron or admin request after a site takes the release, the rows it already holds are turned over, and a site that never saved its login protection or declared a mode is given a row that says so. Until then each is read as before, with the same answer: a hidden login address stays hidden and keeps its slug. Nothing reads these options differently. The front page of a fresh install runs three fewer queries (DECISIONS #366).
Fixed
- A careers application is accepted on a Windows host. On a server that runs Windows, every application sent to
POST corex/v1/careers/applywas refused (422,cv_move_failed), whatever the CV. PHP names an uploaded file's temporary copy with backslashes there (C:\Windows\Temp\php1A2B.tmp), and the route passed the whole description of the file throughwp_unslash(), which removed them: the path handed on named no file. Measured with a real upload on Windows: refused before, stored after, the file kept byte for byte. The route now reads the file as the forms route does, from the request, cleans only the name and the type the browser gave, and hands the path...
CoreX v0.45.2
Two changes on top of v0.45.1, both for a form defined in code.
A form's notification email names the file it was sent with and links to the submission. The email printed the number the file is stored under. It prints the file's name, and a line under the answers links to the submission in the inbox, where whoever may read it opens the file. The file is not attached.
The inbox's search finds a submission by the sender its row shows. A search for the name or the email shown in a row answered "0 accessible submissions" for every form defined in code.
Nothing to set and nothing to rebuild. Read Client impact if a site writes its own notification emails: CoreX's email is not the one such a site sends, and its listener is handed what it needs to add the same link. A search does more work than it did; the measure is below.
Changed
- A form's notification email names the file it was sent with, and links to the submission (spec 081, Phase G; DECISIONS #319). The email printed the number the file is stored under ("Cv: 224"). It prints the file's name, and under the answers a line says the file is opened from the submission, after signing in to the site, with a link that opens the Submissions inbox on that submission. The file is not attached: that is the owner's decision, because a file sent to a mailbox cannot be taken back, and the inbox gives it only to whoever may read the submission. An email of a submission with no file is as it was.
Added
- A form's listener can point at the stored submission.
FormSubmittedEvent::submissionId()is the id of the submission, once the listener that stores it has run, andCorex\Mail\SubmissionAddress::of($id)is where it is read in the admin.Corex\Forms\Submission\UploadedFileNames::in($slug, $values)gives the name of each file sent with a form.
Fixed
- The inbox's search finds a submission by the sender its row shows (spec 103, T110 to T113; DECISIONS #318). A submission of a form defined in code showed its sender's name and email in the row, and a search for either answered "0 accessible submissions": the search read two fields only a flow's submission has. It now looks where the row reads the sender, in the answers named
name,full_name,first_name,emailandemail_address. The search on CoreX → Data → Form submissions is the same one and finds them too. It does not look in the other answers.
Client impact
- A site that writes its own notification emails (a form that lists its own listener) is not changed by this: CoreX's email is not the one it sends. To link its own email to the submission, list
StoreSubmissionListenerbefore its listener, read$event->submissionId(), and ask the container forCorex\Mail\SubmissionAddress.$event->valuesstill holds a file as the number it is stored under. - A routed email template that prints a file's answer (
submission.<field>) prints the file's name where it printed that number. The address is in the context assubmission_url. - Nothing to rebuild: no script or stylesheet changed.
- The search finds submissions already stored: nothing is written to them, and there is nothing to run. A form whose name or email question has another name than the five above shows no sender in its row, and is found by its form.
- A search does more work than it did, because it now reads the senders of forms defined in code, which it used to pass over. Measured on 10,000 submissions, the search's statement took about a third of a second where it took a tenth; that is still less than listing the inbox with no search (DECISIONS #318). It was not measured on a smaller site.
CoreX v0.45.1
One fix, reported from a client site on v0.45.0: a file sent with a form could not be opened from its submission. Under "Answers" in the Submissions inbox there was the number the file is stored under and nothing to press. The pane now shows the file's name as a link, an export names the file, and who may open it is who may read the submission.
Nothing to set and nothing to rebuild. Two things are not changed by it and are still wrong: the notification email of a form with a file prints that number and carries no file, and CoreX → Data → Form submissions prints it too.
Fixed
- A file sent with a form is opened from its submission (spec 081, Phase F; DECISIONS #317). Reported from a client site on v0.45.0: under "Answers" in the Submissions inbox, a submission that carried a file showed the number the file is stored under (
224) and nothing to press. The pane now shows the file's name as a link, and pressing it downloads the file. It says "File missing" when the file is gone, and a file question nobody answered is not listed. The same in the trash, until the submission is deleted for good. - Who may open it is who may read the submission. The link is to an address of the submission's own, checked on every request against the inbox's rule: the person manages submissions and their scope allows that one. A role that was given the inbox and is not an editor opens the file; an editor who was not given the inbox does not. Signed out, or with a link made for somebody else, no file is given.
- A submissions export names the file. A file's column held the same number. It holds the file's name, or "File missing".
Client impact
- Nothing to set, and nothing to rebuild: no script or stylesheet changed.
- A site whose own code reads
GET corex/v1/submissions/{id}finds, for a file's answer, an object (id,name,url,missing) where there was a number. - Not changed by this, and still wrong: the notification email of a form with a file prints that number and carries no file, and CoreX → Data → Form submissions prints it too. Both are in
PROGRESS.mdunder "Open, and not hidden".
v0.45.0
Everything on main since v0.44.0, again with no pull request left open behind it: three things built, and a run of fixes.
A release is installed from the admin. On CoreX → Releases a site on a host with no command line installs its next release, and goes back to the one before. It has not been run on a shared host yet: make the first one a release that changes nothing important, with somebody watching. This release itself still has to reach a site the old way.
A reply is a designed email. It is written in an editor, previewed as the email it will be, sent with a plain-text version beside it, in the site's own colours, logo and footer or its own template, and kept on its submission. The reply box says, before anything is typed, when a reply will not be delivered.
Several data models are exported in one go, and a column that holds personal data leaves the site in a file only with a person allowed to export personal data. Until now subscribers, job applicants, login attempts and the activity log's actors were exported with no confirmation and no right asked (Security, below).
Fixed, mostly in dialogs: the corex/modal and corex/drawer blocks (closed by a press that began inside them, larger than the window, title and close button scrolled away, no name without a title, nothing to read with scripts off), the admin's own dialogs closed the same way, and a secondary button drawn with two borders.
Read Client impact before a site takes this. What acts on a running site without being asked: a person who is not an administrator loses the personal columns in a Data export until given "Export personal data"; Data export files older than 30 days are removed at the first daily clean-up; on a production site with no delivery provider, or with live delivery off, Send reply is switched off; a reply's email looks different; and a cached page holding a corex/modal or a corex/drawer has its old markup under the new stylesheet until the cache is cleared. A site that implements SubmissionEmailGateway or DataExportStore itself has methods to add. Building needs a rebuild of plugins/corex-config and of addons/corex-ui.
Added
- A release is installed from the admin (spec 107, slice 4). On CoreX → Releases a package that was read and not refused can be installed. The screen states what installing does and gives the recovery link, to copy or save as a file, before it asks for the version to be typed. Then the site unpacks the package beside itself, checks each folder against the package's own measure, copies CoreX's tables as they are, and puts the release in place by renames written down first. The request after that is answered by the release just installed: it brings the database to the release and lists what moved, and only then is the release recorded as the site's. Each step is its own request, the screen says which one the site is at, and an installation whose browser went away is gone on with by whoever next opens the screen and may install releases (DECISIONS #307).
- A folder a release owns is replaced whole. A file the release before shipped and this one does not is not left on the site: it is in the kept previous release. A test is named for the day this was missing (2026-10-11, pattern files of an earlier theme left by extracting a zip over it). A folder the running release owned and the package does not hold leaves the site with the previous release, and the screen names each before the administrator confirms.
COREX_ALLOW_RELEASE_INSTALL. A site that setsDISALLOW_FILE_MODScould not install a release, and the screen told it to lift the setting. One line inwp-config.php,define( 'COREX_ALLOW_RELEASE_INSTALL', true );, now allows a release to be installed from the Releases screen and nothing else: WordPress's own installers, updaters and editors stay off. The screen gives the line where it is needed.--with-plugin=<folder>on the package builder. A plugin that is neither CoreX's nor the site's own (a mail plugin, say) is named tonpm run build:dist, any number of times, and is then a folder of the release like the others: listed, measured, checked on the site and replaced whole.corex-release.jsonlists such plugins underthird_party_plugins.- A visitor is held off while a release's files are in place and its database is not. WordPress's own maintenance answer, for those seconds, from the swap until the finishing request; it lets through the one request carrying the installation's key.
- A copy of CoreX's tables before a release changes them, one for each table in the schema registry, named
<table>_cxrel_<yyyymmddhhmm>. Kept for a person to read from; nothing puts one back. One set is kept: an installation removes the copies of the one before it. - Going back to the release before, from the screen (spec 107, slice 5). CoreX → Releases shows which release is kept and which replaced it, says what going back does not undo, and puts the previous release's folders back in one action confirmed by typing its version. No change to the database is reversed, and the answer says so (DECISIONS #310).
- A return made through the recovery link is found. The link works without CoreX, so CoreX cannot hear of it. When the Releases screen is next opened it finds the folders were put back, records the return as one nobody is known to have made, sets the site's record of its release right, and removes the newer release's folders and the recovery file.
- What is kept goes after its time, when the screen is opened. A copy of the tables after 14 days; a package, or part of one, that was sent and never installed after 7. No scheduled job does this: it happens when somebody opens Releases.
- What happened here. The screen lists each installation, refusal, return and installation that did not complete or was given up, newest first, with who did it and when.
- The screen says it is not a backup, where the running release is stated.
- Two guides for a host with no command line (spec 107, slice 6).
docs/en/05-deployment/releases-from-the-admin.md: building the package, a third-party plugin in it, the line for a site that setsDISALLOW_FILE_MODSand what it gives, what is replaced and what is not, the database step, the way back and what it does not undo, each refusal, and what is left on the host.first-installation-by-hand.md: the one installation that is still done by hand, and how a site that has been updated by unpacking zips moves to the screen. The other deployment pages point to them. - The reply box says, before anything is typed, when a reply will not be delivered, and where that is changed (spec 106, slice 1). On a production site a reply is delivered only when CoreX → Settings → Mail has a delivery provider chosen and live delivery on. Nothing beside the box said so: a reply written on a site without them was refused. The Reply section now says which of the two is missing, links somebody who may change settings to the Mail settings, tells anybody else who can, and switches Send reply off until it is set. On a development site, and a staging site with live delivery off, it says a reply is kept in Email Studio and delivered to nobody. The statement comes from the decision the sending itself takes, so the two cannot disagree (DECISIONS #305).
- A reply arrives as a designed email, with a plain-text version beside it (spec 106, slice 2). The site's logo, or its name, above the message on a card with CoreX's brass edge, and a footer naming the site and linking to it. It holds at phone width, has a dark palette for a mail client that asks for one, reads right to left on a right-to-left site, and lets each paragraph take its own direction, so an Arabic line in an English reply starts from the right. The same words go with it as plain text, with links written out and list items marked, as the alternative part of one message. The reply used to be wrapped in a bare shell that set no type, no colour and no footer, and was sent as HTML alone (DECISIONS #308).
- A site gives its emails its own colours, logo and footer, or its own template (spec 106, slice 4), from its own settings or its own plugin and with no framework file changed. CoreX → Settings → Mail has an Email accent colour, an Email logo and an Email footer line. The filter
corex_email_brandreaches the other colours. The filtercorex_email_designreplaces the template, andwp corex make:email-design <Name>writes a working copy of the standard one into the site's plugin to start from. A site's design that throws, answers nothing or leaves the message out does not stop a reply: the email goes in the standard design, and the people who manage email are told which design failed and how (DECISIONS #311). The guide is "A site's own email design". - A reply is written in an editor, and previewed as the email it will be (spec 106, slice 3). The message box has bold, italic, bulleted and numbered lists and links, from a toolbar or from the keyboard (Ctrl or Cmd with B, I and K; with Shift and 8 or 7 for the lists). A link is asked for in the page, and one that goes anywhere but the web, a mailbox or a telephone is refused there. What is pasted keeps that formatting and loses the rest. Each paragraph reads in the direction of what is written in it. Preview shows the email the server will send, in the site's design, at the width of a wide screen or of a phone, with its plain-text version; the email that is then sent is that one, to the byte. The box was a plain text area and there was no preview (DECISIONS #313). A draft kept between visits is not built yet.
- The colours and type of a CoreX email are defined once, in the email add-on (
Corex\Email\Design\EmailPalette,EmailBrand), for every email drawn from them. They were inside the Guides add-on's support message. - A reply is kept on its submission and listed there: i...
v0.44.0
A release to stand on: everything built since v0.43.5, with no pull request and no issue left open behind it. A submission can be moved to a trash, restored and deleted for good, and the trash empties itself. Exports can be PDF. A form defined in code states its own wording, can be drawn with a site's own markup, and is challenged by reCAPTCHA, Turnstile or hCaptcha. The admin shows what is coming while it loads, and every action marks the control that was pressed. The role matrix on Access & Abilities can be saved, which it never could. CoreX → Releases reads a release package given to a site and says what it is; it installs nothing yet.
It is a minor release with a long Client impact, because it is many changes taken at once. Read that section before a site takes this. The ones that act on a running site without being asked: a submission in the trash for more than 30 days starts being deleted, with its files; a site with Turnstile or hCaptcha keys saved starts challenging; a site with the mail queue on and no Action Scheduler starts deferring its mail to WP-Cron; and a choice field refuses a value its options do not declare. Building needs npm ci, composer install (a new dependency, mPDF) and a rebuild of plugins/corex-config.
Added
- A release can be unpacked beside a site, checked, and put in place by renames that are written down first (spec 107, slice 4, the first part). Only the folders a release owns are unpacked, into the installer's own folder, a request at a time; each is compared with what the package says it holds before any folder of the site moves. The swap is a list of renames in a journal: cut off half way, the next request finishes it, or puts every folder back when one will not move. Nothing calls it yet: no route, no screen (DECISIONS #300).
- An installation has its maintenance answer and its way back (spec 107, slice 4, the second part). While a release is put in place WordPress itself answers visitors "briefly unavailable", from a
.maintenancefile that lets through only a request carrying the installation's key. A must-use plugin written beforehand puts every folder back when asked with that key, and uses nothing of CoreX, so it works when the new release does not load. Nothing calls either yet (DECISIONS #301). - The Submissions inbox shows what is coming while it loads (spec 108, slice 6, the last). The list is a table of placeholder rows until its first answer, and keeps its rows, dimmed, while a filter or a page is on its way; the count above it waits with them. An open submission is drawn as its sections until it is read. In the export dialog a count that has not arrived is a bar where the number will be, and the past exports are drawn as coming until they are known. WordPress's spinner is no longer used anywhere in the CoreX admin (DECISIONS #298).
- Every action in the inbox marks the control that was pressed and cannot be sent twice: Undo, the bulk preview, the three confirmations, and in the pane: restore, mark read or unread, send reply, resend, open log, add note, status and owner. In the pane one request is out at a time, and the others wait until the submission has been read back.
- CoreX → Releases: a screen that says what a site is running and reads a package given to it (spec 107, slice 3). It says which release the site is running and for whom, and what on the host stands in the way of installing one. A package is chosen and sent in parts, with how much of it the site holds as its progress; it goes on from where it stopped if the connection drops. Once it is there the screen states what it is before anything changes: its release, when it was built and for whom, what it would replace, how many files and how much room. A package the site will not take is refused in the site's own words. Nothing is installed from this screen yet, and the statement says so (DECISIONS #296).
- A release package can be given to a site, in parts, and read there (spec 107, slice 3, the server's half). Five routes under
corex/v1/releases: what is installed and what the host cannot do; a package received in parts, which goes on from where it stopped if the connection drops and is kept only if it is the file that was sent; and what a package on the site is, or why it is refused. A new ability,corex_manage_releases, holds them. There is no screen yet, and nothing here installs anything (DECISIONS #294). - A site can read a release package and refuse a wrong one (spec 107, slice 2). The checks a package gets where it lands, before anything of it is unpacked: it is a zip, it describes itself, it is for this site's client, this host can run it, it holds every folder it says it does, and nothing in it would be written outside the package. Each refusal is a sentence an administrator can act on. Also here: what stops a host installing at all, and the installer's own folder,
wp-content/corex-releases/. Nothing on a site calls any of it yet; the screen is the next slice (DECISIONS #293). - Insights and the setup wizard show what is coming while they load (spec 108, slice 5). An Insights card shows a placeholder until the last results have arrived, where it read "Not run yet" about a check that may have been run an hour before; the widgets under the cards hold their place, where the screen was two cards and then seven. The setup wizard shows the step that is coming, where the form for a browser without scripts stood and was then swapped for the wizard (DECISIONS #291).
- Forms and flows, and Email Studio, show what is coming while they load (spec 108, slice 4). The catalog of forms shows rows that are not there yet, where it showed "Loading forms…" over whatever it had; opening a flow shows the editor that is coming, where the catalog stayed, disabled, until the flow arrived. Email Studio shows a placeholder under its tabs until it has been read; choosing a template shows the editor that is coming, and marks the template that was chosen (DECISIONS #290).
- The Data screen shows what is coming while it loads (spec 108, slice 3). The records list shows rows that are not there yet, the height of the rows that replace them, where it showed WordPress's spinner. A sort, a filter, a search or a page turn keeps the rows on screen, dimmed and out of reach, with the total above them; the search box asks when typing pauses, not for every letter. A record opens on the press, with a placeholder where its fields will be. The export history and the migration history show a placeholder, where each said "none yet" until its answer said otherwise (DECISIONS #289).
- A button that is working shows the CoreX loader and cannot be pressed twice (spec 108, slice 2, first part). A ring in the button's own colour, in place of its label, at the same width. On the Notifications screen every action has it: each notification's own, Mark all as read on the screen and in the header drawer, and the preference boxes, which now wait for one another. The four buttons that showed WordPress's striped "busy" (export, the Data confirmation, the import dry-run, the migration confirmation) show it too. In Email Studio and in Forms and flows, where every button on the screen was disabled together while any request was out, the one that was pressed shows it and the others wait. The Data screen's import, migrations, export history and record dialogs, Blog Pro, access requests, the Security save, Insights, the setup wizard and the captcha test have it too, and none of them changes its label to "Saving…" any more (DECISIONS #285, #287, #288).
- Notifications show what is coming while they load (spec 108, slice 1). The Notifications screen, its preferences and the header drawer show a placeholder in the shape of their content until the first answer, where each showed a sentence, and none shows "nothing here" before it has been told so. A filter, a view or a page turn keeps the list on screen, dimmed and out of reach, until its replacement arrives, where the list was removed for a line of text; the pager stays, and keeps the focus. A load that fails says so with Try again. Nothing moves for a person who asked for reduced motion. The pieces (
CorexLoadable,CorexSkeleton) are shared, and the other admin screens are moved to them in later slices (DECISIONS #284). - A hosting package says what it needs and what it holds, and is one zip (spec 107, slice 1).
corex-release.jsongains the PHP and WordPress the release needs, the WordPress it was built with, every folder the release owns, and each folder's files, bytes and hash.npm run build:dist -- --zipwritescorex-release-<client>-<version>-<built>.zipbesidedist/. This is the ground for installing a release from the admin; nothing on a site reads it yet (DECISIONS #282). - The Submissions inbox has a trash (spec 105, slice 1). A submission is moved to it from its pane or as a bulk action, after a confirmation that says how many, and the notice that follows offers Undo. Trash, beside Inbox above the filters, lists what was moved there with who moved it and when. A trashed submission is read and nothing else until it is restored, from its pane or in bulk, exactly as it was. Reported from a client's production site, where a test lead could not be taken out of the inbox. Each action is in the submission's own history and, once, in the activity stream, with none of what a visitor submitted.
- A trashed submission is CoreX's to keep. WordPress deletes a post from its trash for good after 30 days, and at once on a site set to skip the trash. A submission moved to the trash from the inbox is outside both.
- The trash empties itself, on its own clock (spec 105, slice 3). A trashed submission is deleted for good after a number of days: 30 unless the site sets another under Submission retention, and never when it sets 0. The daily clean-up does it, with everything a deletion by hand removes...
CoreX v0.43.5
One change on top of v0.43.4. The 500 that failed the browser job now and then was PHP refusing a correct argument, and nothing in CoreX or in anything stored: the job now says what threw in its own output and runs without PHP's JIT, which the runner had switched on unasked. Found while ruling flows out, and fixed with it: one stored flow that cannot be read no longer empties every list of flows, and storing a flow can no longer leave half of one.
For a site it is a patch, unless its own code builds a FlowRepository, calls FlowService::search() or reads the text of the pipeline's log line. Client impact has those.
Fixed
- One stored flow that could not be read emptied every list of flows. A flow is a post and three rows of post meta. A flow whose payload was missing, or held a date that would not parse, made
GET corex/v1/flowsanswer 422 or 500 for all of them, and the Forms screen listed none. The form filter on Submissions and on Data, and the flow counts on Overview and Insights, read the same list and showed no flows without saying why. Such a flow is now left out, the others are listed, and PHP's error log names the record and what was wrong with it (Stored flow record 31267 could not be read and was left out (...)). A flow that points at a draft that was never stored is left out of the Forms list the same way. - Storing a flow could leave half of one. The row a list selects a flow by was written first and the payload last, so a request that stopped between them left a flow no reader could build. The selecting row is written last. A write that fails stores nothing and the request is refused.
- The log line for a 500 behind a CoreX REST route says what threw. It was
Middleware pipeline error:and the exception's message. It now carries the exception's class and the file and line as well. - The browser job prints what the server said, and serves the suite without PHP's JIT. It prints the last 40 lines of PHP's error log and php-fpm's OPcache status in its own output on every run. Eight inbox specs failed on 2026-10-08 on a 500 whose cause was one line in an artifact. That line showed PHP refusing a correct argument against a type it could not name, and nothing wrong in CoreX or in anything stored (DECISIONS #268). The first status the job printed showed the runner's php-fpm running the tracing JIT, which nothing had asked for. The job now switches it off and checks that it is off. That the JIT caused the fault is not proved.
Client impact
GET corex/v1/flowsleaves out a flow it cannot read, where it answered 422 or 500 and listed none. A site that has such a record sees its other flows again on the Forms screen and in the form filters. The record is still stored and its slug is still taken, so a new flow cannot use that slug. PHP's error log names the record's post id; to free the slug, delete thatcorex_flow_recordpost.GET corex/v1/flows/{id}for such a flow answers 422 with "Stored flow record N could not be read." It answered 422 with the reader's own message, or 500.FlowRepositorytakes aBootLoggeras its second constructor argument, andFlowService::search()is nowlisting(), which returns each flow beside its current draft. Code that takes either from the container is unaffected. Code that builds the repository itself or callssearch()has to change.WpFlowStore::create()throws aDomainExceptionwhen a row cannot be written. It returned the post id of a record without that row.- Anything that matches the text
Middleware pipeline error:followed by a message now finds the exception's class before the message and(File.php:line)after it.