Update-Manager
Aktuelle Version
3.5.0-beta.11-b751dd2c
Update verfügbar
3.5.0-rc.14
patchVeröffentlicht: 2026-07-28
Added
- Publish from MarsEdit, Byword, Ulysses, and Open Live Writer: A WordPress-compatible XML-RPC endpoint (
/xmlrpc.phpand/xmlrpc/{collection}) lets writing apps that already speak WordPress publish straight into ablog-schema collection — list existing posts, create and edit new ones, manage categories and tags — authenticated with a scoped API key rather than a real password. It's off by default (Settings → WordPress Publishing) since an exposedxmlrpc.phpis a routine security-scanner target, and it's a Pro-edition feature. Two honest limits worth knowing before enabling it: media upload is not supported in v1 — images must be added in the Total CMS admin, and MarsEdit specifically will refuse to publish a post that contains one until you strip it out — and iA Writer is not covered at all, since it publishes over the WordPress REST API rather than XML-RPC. Access groups are not consulted for these calls; the API key's own scopes are the complete authorization story - Starter sites now load the core stylesheets and scripts: The minimal, blog, business and portfolio starter layouts render
{{ cms.assetsHead() }}and{{ cms.assetsBody() }}, so a freshly scaffolded site picks upcontent.css,cms-grid.css,gallery.cssandpagination.cssalong withcontent.js,gallery.jsand HTMX. Without them{% cmsgrid %}grids and galleries rendered unstyled and Load More had no HTMX to drive it. The head hook sits before the starter's ownstyle.cssso a site's CSS still wins the cascade. Sites already scaffolded from a starter own their copies of these templates and keep them as they are — adding the two lines by hand picks up the same assets, and the WordPress publishing endpoint's discovery link along with them
Fixed
- Admin uploads were rejected from rc.13 onward: Requiring a CSRF token on session-authenticated
/apiwrites covered the form posts but missed the uploads — the Dropzone behind the image, file, gallery and depot fields builds its own XHR and never sent the header, so every upload in the admin came back 403. A verified same origin is now accepted in place of the token, and a single shared policy decides for both auth middlewares, the CSRF middleware and extension routes rather than each carrying its own rule. Cross-origin requests still fail even with a valid token, so a leaked one cannot be replayed from somewhere else, and a request arriving with no browser origin headers falls back to the token as before. The browser stamps the origin and script cannot forge it, so it proves what the token proves without every client having to send anything — and it catches whatSameSite=Laxpermits through, since a sibling subdomain is same-site but a different origin - Price fields showed nothing instead of zero: The
pricefilter decided emptiness with checks that spared the integer0and the string'0'but not the float0.0— which is what a summed or calculated price actually is — so any template totalling prices rendered a blank cell when the total came to zero. Emptiness is now decided by whether the value is numeric at all, so every real number formats and only genuinely absent values blank out - A tag in help text could swallow the rest of the admin page: Schema help is rendered as HTML, so a field documenting the
<title>tag emitted a real<title>element — and because that element's content is parsed as raw text, the browser treated the remainder of the page as its contents. The form silently truncated from that field down, with a valid response and nothing in the logs. The handful of tags that behave this way (title,textarea,script,style, and similar) are now escaped to visible text; all other markup in help still renders, so no existing schema changed - Rejected deck data now says which rule it broke: Importing a deck through JumpStart, the API, or a script could fail with "Deck must be a dictionary of named objects" for four different reasons — a list instead of a dictionary, an invalid item key, an item that isn't an object, or an
idthat disagrees with its key. The message described the valid shape without identifying the problem, which made a hyphen in an item key (the likeliest mistake, since the admin converts hyphens silently and only hand-written JSON hits the rule) a hunt through the whole payload. Each cause now reports itself, names the offending key, and suggests the corrected form. Two shipped schemas also advertised hyphens as valid deck keys in theirpatternPropertieswhen the runtime rejects them — corrected, so schemas copied as a starting point no longer inherit the wrong pattern - API keys scoped to one collection could also reach a similarly-named sibling:
ApiKeyPermissionChecker::allowsPath()matched an API key's granted paths by bare string prefix, so a key an operator scoped to/collections/blogalso matched/collections/blog-archiveand/collections/blogroll, and a key scoped to/uploadalso matched/uploads— any request path that merely started with the same characters as the granted path, regardless of where the next segment began. No key ever reached content outside the tree its granted path named, but that tree was wider than what the admin UI implied when scoping the key. A granted path now only matches on a segment boundary, so/collections(or*) still grants everything beneath it and/collections/blogstill grants itself and its own subtree, but nothing that merely shares its prefix - Privileged user fields would not save with authentication disabled: On an install running
auth.enable = false, toggling a user's Active flag — or editing groups, expiration, the login limit or passkeys — returned a success response and then reverted to the stored value, so it read as a broken form rather than a denied write. Both auth middlewares return early in that mode without marking the request trusted, so the field policy went looking for a super-admin actor that cannot exist when authentication is off, and every privileged field reverted permanently for everyone. The policy now stands down in that mode alongside the other components that already did, which also settles an internal disagreement: the admin rendered those toggles as editable because it treats auth-disabled as admin, while the write path refused them - A neutralized field write now leaves a record: A non-admin with access to an auth collection could edit a user, save, and be told it worked while
active,groups,expiration,maxLoginCountandpasskeysquietly reverted. Ordinary fields saved, so the request half-applied with nothing anywhere to explain why — which is what made it expensive to diagnose on a live server. Each neutralized write is now logged to the access channel with the actor, the collection and object, and the names of the fields reverted or stripped; names only, since passkey values are large and credential-shaped. The guard also compares values rather than reacting to a field merely being present, so a form that posts every field no longer registers an attempted write where nothing actually changed - Setup Default Collections created collections nobody asked for: The routine looped over every reserved schema, including the ones that exist only to be embedded in another schema through
schemaref— automation triggers, the MCP sub-objects, sitemap meta, preset items — so each produced a junk top-level collection the operator never wanted. An embedded schema and a standalone one are structurally identical, both declaringid/type/properties/index, so there is nothing to detect: membership is now an explicit list covering 22 of the 33 reserved schemas, and the old skip-list forblog-legacy,builder-pageand the reference schemas falls away because those simply are not on it
This installation is managed by Composer. Run composer update totalcms/cms to update.