Changelog
Every release since the 1.0 commercial launch, newest first. This page is written from the plugin’s own readme, so it says what actually shipped.
2.2.0
current
- Renamed: the plugin is now WP BaseStation. 2.1.0 made every audit work on any theme with any builder, and the old name still said one builder. The plugin folder, main file, text domain, admin page slug and REST namespace all move to
wp-basestation. Nothing you already have breaks. - All 100 tools are renamed
station_*, and the pre-2.2.0divi_*names are still accepted silently, so a saved skill, a site memory or a model context holding the old names keeps working and is journaled under the new name. The manifest lists the canonical 100 only. - The pre-2.2.0 REST namespace still serves every route, byte-identically, so a connector added before this release keeps working without being re-added. Undocumented and unadvertised.
- Settings, tokens, snapshots, history and the licence all carry over. The storage keys do not move, and the licence record is migrated to the new product slug the first time 2.2.0 loads, so no key needs re-entering.
- Upgrading from 2.1.x: install and activate WP BaseStation while the old plugin is still active. It stands by with a notice rather than loading twice; deactivate the old plugin and it takes over on the next request. Leave the old folder installed, or delete it knowing that its uninstall routine removes the shared settings.
- New mark, new admin skin. The spire-and-orbit mark, a steel and cyan palette across the admin, and a WordPress-wide tagline. The dedicated auth header follows the product (
X-BaseStation-Key); the two older names are still read. - Verified end to end before release: 2,441 checks green through a connector still addressing the pre-rename namespace and tool names, 1,432 green on a Divi-less install, 2,435 green on this site.
2.1.0
current
- Site Health — the seventh audit, and the first that reads the install instead of its pages. station_audit_site group="site" (and station_check_site_health, free) works on any theme with any builder: WordPress, PHP and database versions against their support windows; pending updates; inactive and abandoned plugins; the security posture (guessable admin logins, open registration, XML-RPC, user enumeration, login protection, backups, salts, security headers, directory listing, mixed content); database bloat; content hygiene (sample content, soft 404s, robots.txt, empty menu locations, comments); SPF, DMARC, MX and PHP mail(); and WordPress core's own Site Health tests folded in. Every network probe is cached, time-boxed and reported as unchecked by name when it cannot run, and every run lists what each self-fetch actually received.
- Hardening switches. Seven reversible switches applied on every request — XML-RPC off (endpoint answers 403, method table emptied), hidden version strings, no user enumeration, security headers, HSTS, file editors off, sitemap in robots.txt — through station_set_hardening or station_fix_finding on the matching health finding, each journaled for station_undo_fix. Two content fixes with their own undo: trash the sample post and page, close comments.
- Document-level accessibility, any theme. From the rendered home page: a missing <html lang>, no skip link, no landmarks, a viewport that blocks pinch-zoom, duplicate ids, positive tabindex, autoplaying sound, and a site-wide focus-outline removal. On pages read from their render (every Elementor, Beaver, Bricks page) the form-label, button-name and table-header checks are now decided, not deferred.
- Vendor-built pages are identified per page. A Beaver Builder page on an Elementor-led site was labelled Elementor and audited as an empty, clean page. Each page's builder now comes from its own data — labels, edit links and the "fix there" note all name it — and a page whose builder plugin is deactivated is a failure (visitors see nothing), not "rendered at runtime". Block-editor pages on a vendor-led site are read from storage and stay writable; the site context and the skill say which.
- Every publicly queryable post type is audited by the per-page groups — portfolio, team, events, courses — not only pages and posts. A group the active builder cannot assess is refused instead of reported clean.
- Found dogfooding on a live staging site and fixed: the self-fetch parsed one response header (so every header check failed silently); the probe cache did not clear behind a persistent object cache; undoing one hardening fix undid all of them; a physical robots.txt was treated as WordPress's virtual one.
- Self-test: new "Site Health" and "Hardening" groups; suites green in four configurations — Divi 5.12.0, blocks only, blocks with Elementor, blocks with Beaver Builder. 2,437 checks on Divi 5.12.0. 100 tools: 51 free, 49 Pro.
2.0.0
- Measured against Divi 5.12.0. Every Divi-specific verdict was re-taken on a real 5.12.0 install — a 55-module matrix page, one of every content module with one styling write each, read back from a real browser. 55 of 55 emit their background and 54 of 54 emit their text colour on the documented path; the one exception (divi/breadcrumbs, whose trail font path is dead in Divi's own defaults) is now documented with the paths that do render.
- The render probe read the wrong classes. Divi 5.12 numbers a page's instances from the page's own module count — a second render pass that never resets — so the probe predicted _0 and called every styled block "silent" against a stylesheet that styled all of them. It now reads the classes Divi actually rendered and aligns them by ordinal; modules with no Divi 4 shortcode (group, tooltip, breadcrumbs, payment button) are probed by their real class; a block with no rendered instance is listed as unprobed, never silent.
- The WordPress side of a build. Nine new tools that end "ask the owner to do it in wp-admin": site setup (title, tagline, front page, posts page), menus with locations, form discovery (Gravity, CF7, WPForms, Ninja, Fluent, Formidable), media search, a broken-link check, site-wide search & replace (dry-run by default, structure-verified), structured data, and SEO title / meta description per page — into Yoast, Rank Math or SEOPress, or printed by WP BaseStation itself. They work on any WordPress site, Divi or not. 98 tools: 50 free, 48 Pro.
- Seven of eight sections landed outside the wrapper. A cold-start build anchored an insert "after node 0" — the page wrapper — and the tool obeyed, leaving sections the Visual Builder could not edit. Before/after on the wrapper now means inside it, every write folds stray sections back in, and station_add_module returns the node ids of what it inserted.
- A column with no flexType renders full width on 5.12 — the front end never reads the row structure. The write now fills an equal split when the count divides 24, as the Visual Builder would, and warns.
- Gradient backgrounds render on 5.12, literal stops and gradient tokens alike (they did not over REST on 5.11). The "htmlAttributes does not render" warning was measured false and removed; both id/class forms are documented and pinned on a real render.
- Divi 4 icon strings ("||divi||400") draw nothing on Divi 5; the write rewrites them into the icon object Divi 5 reads. Warning node ids now match station_get_tree on every audit.
- A preset store can carry a record under Divi's "default" sentinel — never applied, undeletable, sorted first. It is listed as corrupt with the repair named, and station_delete_preset removes it. Divi's Dynamic Assets module cache is cleared on every write so a slider or tooltip added over REST loads its script.
- Accessibility: the blank template renders no title, so a landing page on it is no longer told the template supplies an H1; widget semantics re-measured on 5.12.0 (still absent); charts announce as images with their title.
- Builder adapters. One core, N builders: a Divi adapter that is a thin delegate to the existing code, and a rendered-HTML adapter that audits any other site from what it serves and refuses every write by name. Tools the active builder cannot serve are dropped from the tool list rather than failing.
- Skill: a new "dynamic" chapter (loop, dynamic-content and display-condition storage shapes copied from real markup), ids and classes, icon objects, gradients on 5.12, browser verification rules, self-test etiquette.
- Self-test: a new "Site plumbing" group and ~40 new pins across the findings above. 2,359 checks, all green on Divi 5.12.0 with the write path exercised; 66 groups.
1.9.5
- The validator passed a shape that fataled the page. A divi/contact-field given an object where its innerContent value is a string validated clean, saved, and returned HTTP 500 to every visitor. From one agent's cold-start build of a 17-section landing page over the MCP — the full field report is on the blog. Values are now type-checked against the module schema (a scalar field given an object is a hard error, dvc_bad_attr_type, naming the node) and every page write runs an in-process render probe and reports render_ok or render_error.
- A bare string on a blurb title, button or image innerContent stored fine and rendered nothing — the renderer reads ['text']. It is coerced to {"text":…} on write with a warning; the schema carries inner_content_shapes.
- divi/blurb advertised imageIcon.advanced.width…image, which Divi stores and never reads; width renders from imageIcon.decoration.sizing…width. The real path is in known_paths, the dead one under renders_from, and writing it warns. Every module schema now returns roots — where sizing, spacing, shadow and border actually live.
- A font variable created a font nothing enqueued. type:font "Saira" resolved and rendered as the OS serif — no @font-face, no Google Fonts link — while the design system called it active. Google families are enqueued on creation, the response says font.enqueued and how, and the performance audit warns about any font variable no stylesheet backs.
- Media URLs are pinned to the request scheme (a site whose siteurl is still http returned mixed http/https); SVG sources are rasterized to PNG; template:"blank" on page create; license.activate_url and a draft preview_url; a row with maxWidth and no width warns.
- Accessibility: a link that sets its own colour inline is rated on that colour; when the audit has to assume the global link colour the finding says so and carries assumed:true.
- Self-test: a new "Field report 1.9.5" group pins every item above. 1,898 checks, all green on the store we dogfood against.
1.9.4
- Guardian runs no longer overwrite each other. All six audit groups stored their run in one option; two groups continuing in the same minute each read it, appended their pages and wrote it back whole, so the slower one erased the faster one's progress. On an 800-page store this was an audit "stalled" at 48% for an hour. Each group now has its own option and a 90-second lock.
- Guardian roll-ups are complete under the cap. Causes were built from stored findings, so once the 600-finding cap dropped notes the counts were wrong and the diff compared two truncated lists. Every finding is tallied into per-cause counters as it is admitted or dropped; the diff uses tallies (basis:"causes") when either run dropped findings and says so.
- Guardian audits published and private content only — a store with 35 legacy drafts scored on pages no visitor could reach. A running batch is a progress report: causes with counts, only failures inline, page ids with the finished run (was 120 KB a call, twenty calls a run). Blog posts in the block editor are an info, not 709 warnings.
- Site QA called Divi's own writes invalid: themeBuilderArea, the Custom CSS group (css), divider hand-off colours and attrName-declared groups like a video's thumbnail. Builder-written keys are accepted; every attrName head counts as a group.
- Legal: a store requires a Refund and Returns Policy alongside Privacy and Terms — detected from WooCommerce or a Divi payment button — and the installer can write one. Document resolution prefers the designated page, then a published page, and only then a draft.
- Contrast, a11y, SEO and performance declare divi/woocommerce-* modules and form shortcodes ([gravityform], [contact-form-7], [wpforms], [ninja_forms]…) as content they cannot read — station_check_contrast returned "no pairs found" on a checkout page and on a page that IS a form, and both read as passes.
- station_run_self_test never said it had paused: a paused run came back as 242/242 "All checks pass" with no status field — 1/7 of the suite read as a verdict. It now reports status, progress and a PARTIAL note until the last chunk.
- station_update_page wrapped block-editor content in Divi's placeholder block, so a page with no Divi block read as a Divi 5 page without builder meta and Site QA failed it. Only Divi content is wrapped; the builder meta follows the content. A product with no description is a warning naming the field, not a "0 words" failure.
1.9.3
- The Guardian findings cap dropped failures on large sites. A run stores up to 600 findings; beyond that, findings were counted and discarded first-come. The audit queue runs in post-ID order, so on a big site the NEWEST pages were audited last and theirs were the findings that vanished — including failures, while six hundred bookkeeping warnings from ten-year-old pages kept their seats. On an 809-item store the plugin's own self-test caught it: a Divi 4 shortcode page created for the test was classified correctly and then dropped from the stored run, so the run said nothing about it and the re-run diff reported it as never fixed. The cap is now severity-aware — notes are dropped first, then warnings; a failure is never dropped — and the truncation note says so.
- Self-test: the four Guardian classification pins read the probe page directly when a run reports drops, and a new pin asserts that a failure on the last page audited survives the cap on this very site.
- Self-test: the two "zero H1s" Design Guardian pins now honour the engine's own template awareness — on a site whose page template renders the title as the H1, a page with no stored H1 is correct and the pins expect NO warning. A new pin asserts a text-module <h2> is never counted toward multiple-h1.
- Self-test: the 'CSS cache + validator' group (nine 1.9.0 pins) was emitted but never registered, so it could not be run by name or seen in the group list; registered, and a CI harness now diffs emitted labels against the registry both ways.
1.9.2
- The one write that could break a store now plans first and refuses the breaking case. station_build_woo_page replaces WooCommerce's assigned shop, cart, checkout or account page whole, by role. On a real client store the cart page was literally "[woocommerce_cart]" — 18 bytes that ARE the cart — and the tool offered to replace it with no plan step, while its enum listed "myaccount" though no Divi 5 registers a My Account module, so the only reachable outcome there was destruction. It is now a PLAN unless apply=true, showing what the page holds and what would replace it; a layout that carries none of the role's functional modules (divi/shop, the cart modules, the checkout modules) is REFUSED unless allow_nonfunctional=true is passed deliberately; and myaccount is refused outright while the live registry has no account module — checked against the install, not a list, so a future Divi that ships one starts working without a release here.
- Rescue and Site QA stop telling owners to rebuild their cart. Both classified WooCommerce's assigned pages as "non-Divi content" and the Rescue fix plan said to rebuild them as Divi 5 — a documented workflow that ends in a broken store. Those pages now get their own bucket, annotated with their role, and Site QA reports them as an info ("this is the store's cart page; its content is correct") instead of a warning.
- The operator restrictions summary now names station_build_woo_page alongside station_update_page as a write that replaces a published page, so an owner reading their own safety settings can see every path that reaches the checkout.
- A throwing write left a stray product in the admin's cart. Checkout modules run WooCommerce code while the page saves and fatal on an empty cart, so the plugin boots a temporary cart with one sample product for the write and restores the cart afterwards. On the first real store this suite ever ran against, the restore did not restore: the sample product stayed in the session after a failed write. The old restore emptied the whole cart and re-added a snapshot — a wide operation whose own failure was swallowed with the original exception. It now removes exactly the item it added, by cart key, touches nothing else, and records what it did so a restore that fails is visible. The self-test also clears the stray product the old code left behind — it sat in the connector user's persistent cart, which no browser session of yours could empty — so the restore check exercises the real path on the next run.
- Ten new self-test checks run the real thing against the store's real cart page: a cart-less layout must plan, must be refused on apply, and must leave the cart untouched; myaccount must be refused even with allow_nonfunctional; Site QA must not file the cart as non-Divi; the summary must name the tool.
1.9.1
- The truncation detector shipped looking in the wrong directory. 1.9.0 measured the compiled CSS under wp-content/uploads/et-cache; Divi writes wp-content/et-cache/<post_id>/. So on every real install the probe answered "no et-cache directory yet" — the one check that exists to catch a silently truncated rebuild could never fire, and a caller reading it saw nothing wrong forever. Found within the hour by pointing 1.9.0 at a live WooCommerce client store. The correct path was already written down in this plugin's own cache-flush comment.
- The markup validator called Divi's own styling invented. It checked attribute groups against the module's builder-panel map, which the schema tool's own documentation warns is not a storage map. divi/woocommerce-cart-notice writes error.decoration.font.* — present in both its harvested paths and Divi's own style defaults — but has no "error" panel, so validating a live WooCommerce checkout reported that Divi's styling "renders nothing". An agent trusting that would have deleted working checkout styling. Groups are now accepted if they appear anywhere Divi actually writes, and an invented group still warns.
- Four new self-test checks: the CSS probe must search where Divi writes and must find a real file wherever et-cache exists, a group Divi ships in its own defaults must not be called invented, and an invented group must still warn.
1.9.0
- An agent can now unbreak an unstyled site. Divi concatenates module CSS and Theme Options Custom CSS into one static file per page and rebuilds it on the first front-end request after any save. On a client site that rebuild came back truncated mid-declaration — 12,820 bytes against a healthy 27,700 — and every page rendered as an unstyled list while the builder looked perfect. The flush that fixes it had existed inside the plugin for releases; nothing exposed it, so the only cure was a person clicking a button in Theme Options. station_clear_css_cache exposes it, warms one request in series so the rebuild cannot race itself, and reports the compiled CSS size before and after — saying so outright when the rebuild comes back short. It is a FREE tool: an install that can see its site broken and not fix it is a worse advert than the revenue.
- Theme Builder writes now report the compiled CSS size, so a truncated rebuild shows up in the tool result instead of on the client's screen.
- Memories can no longer go dark in silence. Only what fits the injection cap reaches a session, and the overflow was dropped without a word — found in the field at 2,486 characters against a 2,000 cap, seven memories stored, every save accepted cheerfully, roughly the last fifth never loading while the owner believed all seven applied. The cap is raised to 3,500 (it was below the per-entry limit times three, so a site inside every documented limit still lost rules), a save that would silence an existing memory is now REFUSED and names which ones, every save reports the budget back, and station_list_memory leads with the verdict in words instead of two unlabelled numbers at the bottom.
- station_list_memory also flags stale memories — ones naming a colour token or pattern this site no longer has. A stale memory is worse than a missing one: it sends every future session after something that was deleted months ago.
- Twelve new self-test checks, including one that fills the store past the cap to prove the refusal fires and names the casualties.
1.8.4
- The connector had two sets of instructions. Overview and the Connection tab each carried their own folded "how to connect" — two step lists that had already drifted apart (one said four steps and mentioned Claude Code, the other said five and did not), on the one screen a new customer cannot afford to be confused by. The Connection tab owns the instructions now; Overview keeps the URL and a copy button, because a credential you cannot find is a support ticket, and links across for the rest.
- The Connection tab reads as what it is: copy this URL, paste it in Claude. The four paragraphs that used to sit under the steps — plan prerequisites, the desktop-app connector cache, stale tool lists after an update — are kept in full behind one "Not connecting?" disclosure, so a working connection stops looking like a problem. The summary names the plan prerequisite outright, because that is the one failure a person cannot diagnose from the steps.
- Four self-test checks hold the line: the Overview renderer may contain no steps of its own, the troubleshooting stays folded rather than deleted, and the plan prerequisite stays inside the fold rather than orphaned above it.
1.8.3
- The cross-site pull handoff never worked — and now does. The single-use ticket a target site redeems anonymously hit a per-user read check that anonymous requests fail on every post, so the first real pull answered 403 on a published page and burned the ticket. The ticket is now the read authorization it was always meant to be, and four new self-test checks run the serve leg exactly as a pulling site does.
- Client reports no longer cry wolf: the since-last-run delta counted informational notes — audit blind-spot disclosures whose own body says there is nothing to fix — as new issues. Only failures and warnings move the fixed / new numbers now.
- station_delete_token’s refusal now names the posts that reference the token, instead of telling you to retarget references it never locates.
- All three found dogfooding 1.8.2 on our own sites: the first real site-to-site pull, the first real client report, the first real token cleanup.
1.8.2
- Theme Builder templates now actually assign. Short conditions like singular:post were stored verbatim and Divi resolved none of them — the template sat Unassigned and never matched on the front end. Conditions are now translated to the ids Divi resolves, and an id the install cannot resolve is refused with the real list instead of stored as a dud.
- Body-only templates no longer lose the site chrome: omitted header and footer slots now inherit the global layouts instead of falling back to the theme’s stock header, and deleting a template can no longer trash a layout another template still references.
- Loop Builder fields (loop_post_title, loop_post_link and friends) now pass the token audit instead of warning that a perfectly working binding resolves to nothing — found building this site’s own blog index.
- Self-test hardening: ten new checks pin the fixes, and fixture reclaim now covers design tokens — an aborted run could leak its test color and false-fail every later tokenize run.
1.8.1
- Audit accuracy fix, found dogfooding this site’s own new blog: Gutenberg and classic-editor content was invisible to the audit collector, so posts measured zero headings and zero internal links — and the SEO audit warned that link-filled posts linked to nothing.
- The collector now runs non-Divi blocks and freeform (classic) content through the same HTML scanner Divi text modules use — headings, links, images, iframes and inputs in posts now count in every audit and in client reports.
- Five new self-test checks pin the fix end to end, through the exact internal-link counter the SEO audit uses.
1.8.0
- A landed fix re-checks its page. The customer panel’s top frustration, verbatim: “I fixed a finding and the tab badge still said ×5.” Every fix door — one-click fixes, the review screens, Fix All, and undo — now re-audits the touched page inside the stored run: findings swapped, counts corrected, and the header badge updated on the spot. The fix message tells you what the re-check found instead of sending you off to re-run a forty-page audit.
- Fix All re-checks inside a time budget. A bulk fix across many pages re-verifies as many as fit in the budget and says plainly when the rest wait for the next run — one sentence never covers two different truths. Score history still only records at finished audits, so the trend line stays a record of real measurements.
- White-label client reports. Settings → Client reports takes your business name and a logo from your Media Library; every exported report then carries your brand and drops ours. The logo is embedded into the report file itself, so the document keeps working offline and in email. Available on every paid plan — the plans differ by sites, not features, and that stays true.
- Eleven new self-test checks pin both features, including that a re-audit never writes score history and that a white-labelled report drops our name without dropping the Divi trademark notice its content still requires.
1.7.3
- Licence seats are released on uninstall. Deleting the plugin now tells Freemius, so a single-site licence frees itself for the next site. This closes the oldest documented bug in the codebase: WordPress runs a plugin’s uninstall.php file INSTEAD of the registered uninstall hook, so shipping that file silently stopped Freemius ever hearing about the uninstall — and the seat stayed burned.
- The cleanup sweep moved to the after_uninstall hook. Same sweep, credentials first and multisite-aware — it now runs after Freemius releases the seat, with a fallback registration when the SDK is absent. Subsites on a network additionally get their cached transients cleared, which the old file only did on the main site.
- The build refuses uninstall.php forever. A resurrected file would silently re-break seat release with no error anywhere, so the packager now fails the build — the same check Freemius’ deployment pipeline runs, moved to where the mistake would be made.
- Three new self-test checks pin that the file stays deleted, that both registration paths exist, and that the sweep only runs during a real uninstall.
1.7.2
- Second dogfood find, same client site: The plugin was auditing its own test fixtures as the customer’s content: probe pages stranded by runs the 1.7.1 lock bug killed showed up as SEO and QA failures on pages the customer never made. Both audits went clean the moment the debris was removed.
- The fix: The probes now carry the swept fixture prefix, the old name is legacy-swept so pages leaked by earlier versions are reclaimed automatically on the next run, and two new self-test checks pin both.
1.7.1
- Found dogfooding, fixed same day: We ran the plugin on a real client site on WP Engine and its own self-test could not finish: chunked runs pinned at the same cursor forever. Diagnosed, fixed, and verified on that same site within the hour.
- The cause: On hosts with a persistent object cache, a transient with a TTL lives only in the cache — never the database — so eviction erased the run lock mid-pause and the resume path reaped the paused run as abandoned.
- The fix: The lock is now a database-backed option with its own expiry, and every read and write of the lock and the paused state flushes the object-cache key. The host cache can neither evict a run nor serve it stale.
- Honest fixtures: Two self-test checks assumed a fresh site whose typography the fixtures could control. On a lived-in site whose own headings join the vote, they now pin what is actually guaranteed — and say why they skipped the rest.
1.7.0
- The connection pill: Every screen of the app now says, at a glance, when the site last heard from Claude — green while requests are fresh, amber after a silent week, grey when no client has ever called in. The pill links to the Connection tab.
- Honest by design: A stateless connector holds no socket open, so there is no true “connected right now” to show. The pill shows the one thing the server actually knows — the time of the last authenticated call — and never pretends otherwise.
- Durable: The timestamp is a latch recorded on every authenticated request, so it survives the activity log aging out or being switched off. The Connection tab reads the same latch and no longer claims a bare “connected” with no time on long-idle sites.
- Pinned: Uninstall removes the latch, and new self-test checks pin the recorder, the reader, the pill states and the cleanup.
1.6.1
- Agent sweep, round two: Four independent adversarial review agents against the whole surface. Twelve confirmed findings, all fixed same-day and pinned in a new self-test group.
- Paywall hardened: A crafted request could run a Pro site-level fix on Free by riding a page id past the gate — closed on both doors, wp-admin and the connector.
- Tokenize verify fixed: A page that also displays one of its colours (a code sample, a style guide) no longer rolls back a clean tokenize with an error.
- Honest contrast math: rgb() channels above 255 now clamp to what the browser paints, so an overdriven value can no longer slip past the AA gate.
- Specimens everywhere: Type-scale findings sourced from your site’s own mined convention now render their specimens too.
- Controls survive errors: A network blip or expired session no longer removes Fix buttons until reload; review panels load once; one audit loop per screen.
- Fix All: An apply must present the plan token of the plan it displayed, and plan and apply now agree on their arithmetic.
1.6.0
- Search previews: SEO title and description findings now show the page as a Google result — the part search engines keep bright, the part they cut struck through, missing fields flagged in red.
- Heading outline: Heading findings open the page’s real outline: every heading indented by level, skipped levels and extra H1s flagged amber. Opens automatically.
- Image evidence: Performance image findings list the actual offending images — thumbnail, file size, and width badges — with honest skips for images the plugin cannot read.
- Type specimens: Font-size drift findings render both sizes as real type, so you can see the drift instead of comparing numbers.
- Color dots: Every hex color named in any finding now carries a swatch dot showing the color itself.
- Fix: Escaped apostrophes are no longer mistaken for three-digit hex colors.
1.5.0
- Fix alt text where you see it. Missing-alt findings arrive with the review already open — the image thumbnail, the best suggestion pre-filled, and the input ready. Describe the picture and Apply, right in the row; the builder link stays for anyone who wants the full page around the image.
- Every audit pill says when it last ran. A compact age on each of the six pills — 35m, 3h, 6d — with the full time in the tooltip. A run older than a week, or an audit never run, shows amber: the point at which the counts stop describing the site.
1.4.3
- The contrast screen passes its own test. The suggested-swatch caption sits on the pair’s own colour, so it now rides in a solid chip that is legible on anything — the one screen about contrast no longer fails it.
- Findings read human-first in Simple mode. The type-scale finding leads with what the Fix button will do before the technical route.
1.4.2
- Hardened by an adversarial review sweep. Three independent QA reviews ran against the new panel code; thirteen verified findings, all fixed same-day.
- Contrast review is stricter about identity. An approval made for one text colour refuses to overwrite a colour an editor chose after the list was made; a value with junk after a valid colour is no longer “a colour”; and every alpha spelling is recognised, so a translucent replacement can never sneak past the AA gate.
- Fix All’s confirm is bound to the plan it showed. If the stored audit changes between plan and confirm, the write is refused and the button re-plans — the write set can never silently differ from the shown set.
- Smaller honesty fixes. The broken-token cause stops offering a fix that couldn’t fix it; the legal publish guard also recognises WordPress core’s own template Privacy Policy draft; waiver-driven score moves say so instead of blaming coverage; draft-page findings link to the editor instead of a 404.
1.4.1
- Design panel render fix. A shadow role’s value printed as raw JSON in a cell that could not wrap, pushing the adopted-roles table’s Override column off the screen. Shadows now read as the shorthand a designer knows — offsets, blur, spread, colour — with the exact stored object in the tooltip. Render-only; no behaviour changes.
1.4.0
- Every audit panel catches up to Design Guardian. One question asked of each audit: can you understand what is wrong and fix it without leaving the panel? All six now answer yes.
- Contrast gets a review screen with swatches. Each failing pair renders as it really is, beside the nearest colour from this site’s own palette that clears WCAG AA — approve it or type your own, with a live preview. An approved suggestion writes the design-system token, and a replacement that would itself fail AA is refused with the ratio it would have had.
- Hardcoded values get a one-click tokenize. Every literal matching exactly one design-system colour becomes that colour’s token, verified with zero modules lost. Ambiguous literals are listed with their candidates, never guessed.
- Fix All shows its plan first. The first click runs the batch dry and lists, page by page, what would change; only the re-armed second click writes.
- Open in builder, everywhere. Every finding row links straight into the Visual Builder on the page it names.
- Simple mode finally reaches the findings. Token JSON reads as its label and tool-speak steps aside for the Advanced view; nothing is ever hidden entirely.
- The score delta explains itself. Open “−1 since yesterday” and it names which audits moved, from per-suite snapshots the score history now keeps.
- Legal drafts publish from the panel — refused while they still carry [REVIEW] placeholders, because a live legal page with blanks in it is worse than a missing one.
1.3.10
- Missing alt text gets a review screen. The audit finding now shows each image, pre-fills the Media Library’s suggestion where one exists, and takes your own words instead — applied per item, journaled, undoable. Empty alt stays the deliberate decorative marker, and an approved description is refused if the image changed since the list was made.
- Design Guardian’s four checks all grow Fix buttons. Slider autoplay switches off in one click — arrows, dots and swipe keep working — heading sizes snap back to this site’s own resolved type scale, and H1 repairs route through the headings engine’s existing guards.
- Generic CTA copy is review-only, deliberately. No rule writes a good button label, so the screen shows each button, where it links, and a mechanical suggestion — an internal link becomes “See that page’s title” — for you to approve or rewrite. A replacement that is itself generic is refused: a fix that re-flags on the next audit fixed nothing.
- Every review write carries every gate a Fix click carries — the free tier’s bound-page rule included — and the self-test grows to 1,714 checks.
1.3.9
- Fixed: the paywall could fail open, and it was a fix in 1.3.8 that did it. 1.3.8 made the free-page binding heal itself when the bound page had been deleted — but it did that inside the read the page gate calls on every single tool call, and that gate does no existence check by design. A binding that could not be resolved became no binding, and all 21 page-scoped tools were waved onto any page.
- The self-test caught it on the first run after the deploy: eight failures in Licensing & tiers, one of them reading “a second page is refused — NO ERROR, FREE TIER REACHED A SECOND PAGE”. It never reached a customer.
- The healing moved to the Overview screen, where a human can see it: a binding pointing at a deleted page now says so and offers to release it, and that release does not count against the three-rebind cap. A paywall that heals itself into having no limit is worse than the stuck state it was fixing.
1.3.8
superseded
- Superseded by 1.3.9 within the hour — a fix in this release made the free-tier page limit fail open. Do not run 1.3.8.
- Fixed: the client report was downloadable without a licence. The handler had a capability check, a nonce, and no licence check at all, and the button was drawn on every audit screen, on every tier, in the default view. Free deliberately gets the whole site-wide audit, so one click turned a free install’s findings into the branded deliverable an agency resells.
- The free tier’s one-page limit could be released and rebound without limit, and the message the agent receives named wp-admin as the place to do it — so it read as the sanctioned remedy. Release, build the next page, release again. Rebinding is now capped at three: enough for someone who bound the wrong page, nowhere near enough to walk a site.
- Snapshot restore is free again. A rollback behind a paywall is worse than no rollback, and the people who need it most — a lapsed trialist, a lapsed customer — are on the free tier by definition.
- Scheduled audits used to render the whole form on Free and refuse at the save, discarding what had been typed. It says it is Pro before the effort now.
- Client report links expire after 14 days and nothing said so; a monthly schedule was deleting last month’s report, including a link already sent to a client.
- The self-test now checks the wp-admin door as a class, not one handler at a time. That is why the report leak survived five releases after six others were fixed.
1.3.7
- First-run pass. The Connection screen states the prerequisite nothing stated: you need a Claude account on a plan that can add custom connectors.
- “Didn’t attach? Run the connection checks” now appears under the last step while a site has never connected. Diagnostics is Advanced-only and Simple is where a new install starts, so the one person who needed the checks was the only one who could not see them.
- Connection says whether Claude has actually called in, and when. “Endpoint live” only ever meant the REST route answers.
- The audit opens the most severe group you actually have, instead of only opening failures — on a site with warnings and no failures, every group used to render closed.
- “How this is scored” on the score card. The reasoning was written out in full where only Claude ever read it.
- Safety switches no longer look saved when they are not.
1.3.6
- Fixed: three writes kept no step back, and one of them said it did. Tokenizing a page’s colour literals rewrote every module’s attributes, wrote directly, and returned “A revision holds the prior content” — with no revision and no undo slot anywhere in the function. False on every site, not only the ones with revisions disabled.
- Theme Builder and Divi Library writes used a bare WordPress revision save, which does nothing on a site with revisions switched off. A header write there had no undo of any kind, and one bad header write is every page on the site. Both now get the same one-step-back guarantee as a page write.
- The self-test says when a run was short of full coverage. Four groups need Divi’s builder framework, which wp-admin does not load, so they are skipped there and run through the connector. Both surfaces behaved correctly and both wrote a “Skipped” row, but the wp-admin headline read “All 1,494 checks passing” while the same suite reported 1,673 through the connector, with nothing explaining the gap.
- The rescue scan lists at most 40 pages per category while its counts are complete, so a site with 200 Divi 4 pages was told 200 and handed 40. The result now says which lists were shortened and by how much.
- “Every finding has a one-click fix” on the first-flight checklist. There are 83 check types and 11 have a Fix button.
- Two strings still called tier gating off by default, which stopped being true in 0.90.0 — one of them in the payload Claude reads at the start of every session.
1.3.5
- The score is now labelled “Autopilot Site Score” wherever it appears. “Site score” read like a WordPress feature; it is this plugin’s arithmetic and it should say so.
- The dashboard’s own capability copy carried the same overstated claims that were corrected on this site, which is worse — that is the copy an evaluator reads while deciding whether to trust the thing. All four now match the code: alt text and heading fixes are journaled and undoable while legal pages arrive as drafts to review; one step back before every page write and a snapshot before every design-system write; rescue classifies up to 300 pages, not “every page”; five auditors read every page while legal reads the site.
1.3.4
- Fixed: the step back kept for sites with WordPress revisions disabled was written and unreachable. Where wp_save_post_revision() does nothing — WP_POST_REVISIONS off, which several managed hosts ship and every “optimise your database” plugin offers — WP BaseStation stashes the outgoing page content in post meta, then told the operator to restore it with revision_id 0. There was no branch for 0, and the function that reads the slot back had no callers anywhere in the plugin. On exactly the sites least likely to have another backup, the recovery instruction was false.
- station_restore_revision now accepts revision_id 0, with the same dry run, the same module-count verification and the same refusal to touch another page’s content as any revision restore. station_list_revisions lists the slot as its own row, first, with its module count and an explanation of what it is.
- Restoring is undoable on both kinds of site now. The restore path called wp_save_post_revision() directly, which does nothing where revisions are off, so restoring the slot consumed the only step back and left none.
- Three tool descriptions and the History screen claimed “every write saves a revision first” — true on most sites, false on the ones this feature exists for. All corrected.
- New self-test group, “Undo slot”, which writes the slot the way a revisions-off site would and drives the whole round trip. The bug survived because every test ran on a site with revisions on, where the slot is never written.
1.3.3
- Fixed: six paid capabilities were reachable without a licence in wp-admin — fixing a cause across every page, scheduled audits, the emailed client report, installing legal drafts, adopting a design system, and restoring one. All six are gated on both surfaces now, and the scheduler refuses to arm or to fire without a licence, so a lapsed site stops rather than quietly continuing.
- Fixing from wp-admin now respects the Free tier’s bound page — the rule the tool surface already applied.
- station_restore_snapshot joined the design-system group, so “Protect the design system” covers it. It rewrites colours, variables and presets site-wide and was the one write that switch could not see.
- The Free tool count is 42, not 43.
- One icon set across the plugin and this site. The ten dashboard icons were Unicode glyphs from six different blocks, two of them emoji codepoints the operating system rendered in colour while the rest stayed monochrome. All inline SVG now, on one 24px grid.
- New “Next” row on Overview: at most three tiles naming the next action and what it does, ordered by what blocks what.
1.3.2
- Fixed: every surgical write — edit, add, move, delete module — was returning the whole page’s token digest instead of the warnings for the node just written. Forty consecutive edits each came back with the same eleven warnings and their full node lists. New warnings still come back in full; pre-existing ones now collapse to one counted line.
1.3.1
- Fixed: the full self-test reported eight failures on a Free site when nothing was wrong. Six were the licence gates correctly refusing paid writes, and two were an adopted design system correctly outranking the miner. Every one of those refusals is now asserted as the correct behaviour it is, on both tiers.
- The full suite is meant to be run from wp-admin on any tier. It now stays green there whether or not the site is licensed, and whether or not a design system has been adopted.
1.3.0
design system
- Reads the design system your site already has. Scans pages, posts, Theme Builder layouts and the Library — presets resolved, newest work weighted heaviest — and proposes your real colours, type, radii, shadows and spacing as a scale rather than an inventory. Adopt it and Claude resolves every design question against it first.
- Four new resolver domains — elevation, radius, spacing, sizing — that answer with a paste-ready Divi 5 attribute fragment at the correct root for the module you name.
- Group presets are now resolved when auditing. Styling that lived only in a group preset was previously invisible to the contrast, accessibility and performance engines.
1.2.0
- Licence keys can be activated after the fact: a masked key field on Diagnostics → Licensing, a one-line prompt on Overview, licence detail with seats used, and a “release this site” control so a seat can be moved.
1.1.0
- Admin UI translated into French, German, Spanish, Italian, Brazilian Portuguese, Dutch, Polish and Japanese.
1.0.2
- Findings table readability: primary finding text at full contrast (10.2:1).
1.0.1
- Self-test reliability: content-classifier checks made deterministic across WordPress parser versions.
1.0.0
launch
- Commercial launch. Tier enforcement on by default; GPL license file; pre-launch security audit fixes — design-guard bypass closed, uninstall data hygiene, endpoint rate-limiting, log secret-scrubbing.
Before 1.0 there were ninety-odd development releases. The two that matter: 0.98.x introduced the unreadable-content architecture, where audits declare what render-time modules they cannot read instead of reporting false counts or false cleans, and closed an API-key leak in page rendering. 0.91–0.97 brought the site score with disclosed arithmetic, per-finding owner waivers, first-flight onboarding, and auto-continuing chunked runs with progress.
