Minn Admin · Docs

Changelog

Every Minn Admin release, in order, with what each one added, improved and fixed.

v0.21.0 - July 24, 2026

The trust release. This cycle is for everyone who is not the person who built the app: the interface gains real translation plumbing so it can meet users in their own language, the app chrome passes a genuine accessibility audit with a suite that keeps it honest, and a plain-words user guide ships inside the plugin, one click from help. The same spirit runs underneath: updates verify themselves against a published checksum before they install, a security policy opens a private door for researchers, a tab left open overnight recovers on its own, and boot rides one request instead of nine so shared hosting stops watching panels trickle in.

Fixed

  • Pending comments stay in the moderation queue: the Overview's Recent activity feed included comments awaiting moderation (author names and all) for every user who could see the dashboard, even though the Comments view, the notification panel and the pending row's own click-through are all reserved for moderators. The feed now applies the same rule everywhere: users who can moderate see pending rows, everyone else sees approved comments only.
  • Test scaffolding no longer ships in the notice pipeline: the two dev-fixture ajax handlers used by Minn's own browser suites lived in the shipped whitelist, reachable (though harmless) on any site. The notice button mapping is now filter-open like the whitelist itself, and the fixture handlers moved to the dev site's fixtures plugin where they belong. Production installs carry no fixture code paths.
  • A tab left open overnight recovers on its own: REST nonces expire after a day, and an expired one used to dead-end the app (every request failed with a raw error toast until a manual reload). Minn now notices the expired nonce, mints a fresh one in the background through WordPress core's own nonce endpoint, and retries the request; a whole page of parallel requests shares one refresh. If the login session itself is gone, Minn says so and reloads into the login flow instead of leaving dead buttons.
  • Typing a license key can no longer be interrupted: a background loader resolving late could rebuild the Licenses tab out from under an open key form, discarding the form and the key being typed before the activation request even returned. A stray rebuild now leaves an open paste form alone; only the renders that legitimately dismiss or replace it (the post-action refresh, Cancel, the inactive-components toggle) still swap it out.
  • Three low-severity hardening fixes from a full security audit: a line-by-line pass over the REST surface, adapters and app shell turned up no serious issues and three small gaps worth closing. A public read of a post no longer reveals the name of whoever happens to have it open in the editor (that "someone is editing" signal is for the dashboard, not the world). The Custom CSS & JS reader now refuses to reconstruct PHP objects from stored data, matching the safe pattern the rest of the integrations already use. And the small block of startup data the app inlines is encoded so a site name or display name can never break out of it. None of these were exploitable in normal use; all three are now closed.

Added

  • A guide for the people who actually use Minn: docs/user-guide.md is the new site-owner manual, covering getting around (the sidebar groups, the command palette, and the fact that right-click works nearly everywhere), writing and the editor's safety model in plain words, daily site care, hiding what you don't use, every keyboard shortcut, and an honest safety section: what happens when you deactivate (nothing), how updates are verified, and who can open the app. It ships inside the plugin so the copy you read always matches the version you run, and it is now part of the release checklist so it stays current. The guide is one click away in the app itself: a User guide button on the About dialog and an "Open the user guide" palette command render the bundled copy in a reader modal, with the shortcuts table and all, no internet required.
  • The app chrome passes a real accessibility audit: every main view now audits clean with axe (zero violations, both themes), and a dedicated browser suite keeps it that way. Screen readers hear each navigation announced and see the active nav item marked as the current page; keyboard focus is rescued when a view swap would have dropped it; every page has a proper top-level heading; the sidebar is a labeled navigation landmark; icon-only buttons and list checkboxes carry real names ("Select Hello world", not silence); sort buttons speak their direction; and users who prefer reduced motion get an interface that stops animating. Muted text and status-chip colors were nudged to meet WCAG AA contrast in both themes: same hues, slightly more present, with pills and dots keeping their original tones.
  • Minn is ready to speak your language: the app now has real internationalization plumbing. Interface strings translate through standard WordPress translation files (the same .po/.pot format every translator already knows), each user sees the interface in their own profile language, and English remains the built-in default so nothing changes until a translation exists. The app shell (navigation, page titles, toolbar) is translated first; the rest of the interface converts view by view. Plugin authors' own labels stay theirs to translate.
  • Boot rides one request instead of nine: the startup burst (notifications, plugin and update caches, core status, the pending-comment badge, post types and the order summary) now arrives in a single consolidated request. Each section is produced by the same route the standalone fetch used, so nothing changes shape, and a section the server cannot provide falls back to its old standalone fetch automatically. On shared hosting, where a handful of PHP workers had to serialize nine parallel requests, the app's panels stop trickling in one by one.
  • Updates are checksum-verified before they install: the release manifest now publishes the sha256 of each release zip, and the self-updater downloads the package, checks it against that hash, and refuses to install on any mismatch. The manifest travels from the GitHub repository while the zip comes from the release CDN; pinning the hash ties the two together, so a tampered or truncated download can never reach your plugins directory.
  • A private channel for security reports: the repository now carries a security policy with GitHub private vulnerability reporting enabled, so a researcher can disclose quietly and expect an acknowledgment within 48 hours. It also includes design notes for reviewers, the properties worth knowing before an audit: the capability gate and per-route permission checks, the descriptor-only integration boundary (third-party PHP never runs in Minn's render paths), the no-unserialize and prefix-scoped-SQL shim rules, and the checksum-verified updater.

Improved

  • The help dialog helps first: the About dialog now leads with what a person clicking "?" actually needs: how to get around, the fact that right-click works nearly everywhere, and how to hide what you don't use, followed by the keyboard shortcuts. The philosophy is still there, condensed at the end, and the User guide button remains one tap away.
  • The plugin and its website finally point at each other: the plugin's listed website is minnadmin.com now (it was the GitHub repository), and the About dialog links to the site and its new shareable docs pages at minnadmin.com/docs. The bundled in-app user guide is unchanged; the web pages are the linkable copies.
  • One listing, not two: the wp.org-style readme.txt is gone. GitHub is the distribution channel, so readme.md and minnadmin.com are the listing surfaces; the FAQ, security notes and user guide now live where people actually read them instead of drifting in a second copy.
  • List pages are ready to search the moment they open: navigating to Extensions (plugins or themes), Content, Media, Users, Orders, Terms and every other list view drops the caret straight into the view's filter box, so typing filters immediately with no click first. It happens once per navigation and politely: a re-render never yanks focus back, an already-focused text field (the palette, a modal input) is never robbed, and touch devices skip it so the software keyboard stays down.

v0.20.0 - July 20, 2026

The consent release. Every consequential action now says what it touches before it happens: updates enumerate what changes and what stays untouched, permanent deletes wear danger styling with plain-stakes copy, and quick reversible verbs keep their one-click ease. Around that spine, comments learn in-place editing and one-click commenter blocking, the content list says who is editing a post right now, Settings closes two more Customizer-era gaps (site logo and site language), Search & Filter Pro and Admin Columns Pro join the license manager, and plugin activation moves to a real admin context so activation hooks that assume wp-admin stop failing.

Fixed

  • Plugin activation works for plugins that assume wp-admin: plugin toggles now run through admin-ajax, a real admin context, instead of the REST plugins endpoint. Activation hooks are written for wp-admin, and some plugins only load parts of themselves there (Breeze skips its ecommerce class outside wp-admin and fataled when activated from Minn on a WooCommerce site). Every activate and deactivate door rides the new path: the Extensions switch, right-click menus, license Turn on, connectors, the Add plugin dialog and the deactivate-Minn modal, with REST as the automatic fallback when admin-ajax itself is unreachable.
  • Add-on families keep their names: the plugin name cleanup trims marketing taglines after the first separator, which collapsed families like Admin Columns Pro's add-ons ("Admin Columns Pro - Ninja Forms") into a wall of identical cards. When two installed plugins clean to the same name, both now keep their second segment, so add-ons stay tellable apart while tagline stripping stays aggressive everywhere else. Search matches the disambiguated name too.
  • Installing several themes quickly no longer fails with "Failed to fetch": a theme install swaps files and can recycle the PHP worker, so a rapid second install landed on the dying connection and errored even though the server was fine. The Add theme dialog now waits for the server to come back, asks the themes list for the truth (an install whose reply died after the work counts as done), and retries once before reporting a failure. Activating from the dialog gets the same recovery.
  • No Comments tab in notifications when comments are off: the notification panel offered a Comments tab even on sites where comments are disabled (the same gate that already hides the Comments nav item). The tab now follows that gate, and an active Comments tab falls back to All if the gate closes mid-session.
  • The notification panel's fifth tab was unreachable: with Comments, Updates, Notices and a System kind all present, the tab strip clipped at the panel edge with no way to scroll. The strip wraps to a second row now, so every kind stays visible and clickable.

Added

  • A confirm that says what it touches: consequential actions moved from the browser's native confirm to a shared Minn dialog with scope disclosure, swept across the whole app. Update everything and the WordPress core update (both of its doors) enumerate exactly what will change (the pending plugins, themes and core version) and what is not touched (your content, media, users and settings), so the biggest button in the app is also the most explicit. Every permanent delete wears the danger styling with plain-stakes copy: plugins and themes, content, media files, comments, users, terms and term merges, menus, widgets, coupons, refund records and emptying a log. Switching the site's theme shares one dialog across all three of its doors (and says out loud that the old theme stays installed), deactivating a license says the seat frees up, a refund says whether the gateway is asked to send money back, and sending a WooCommerce order email says it goes out right away. Confirms stack politely too: Escape over an open modal peels just the confirm, never the dialog beneath it. Quick reversible verbs (move to trash, sign-outs, password resets) keep their one-click confirms.
  • Edit a comment in place: Pending and Approved rows gain an Edit action that opens an inline box with the comment's raw text; guest comments also offer the author name and email (a registered commenter keeps their account identity, so only the text travels). Fixing a typo or stripping a link no longer means a trip to wp-admin.
  • Site logo, in Settings: when the active theme supports a custom logo, the Site tab gains a logo field beside the site icon with the same flows (pick from the library, drag and drop an upload, remove), saving through the exact theme_mod the Customizer writes. Themes without logo support see nothing, matching the Customizer's own gate.
  • Site language, in Settings: the Site tab gains a Site language picker over every installed and downloadable locale (the options-general list). Picking a language the site does not have downloads its pack on save, through the same machinery as the profile's per-user language; your own language stays on Your profile. This closes another named Customizer-era gap from the core coverage audit.
  • The content list says who is editing: a post someone else has open right now wears a quiet "{name} is editing" chip beside its status, on every post type in the list. It reads core's own edit lock (the same lock wp-admin, Gutenberg and Minn's editor already honor between them), so there is no new bookkeeping: a crashed session's lock ages out on its own, and your own open tabs are never flagged. The editor's blocked-open and takeover flow stays the door; the chip means you know before you knock.
  • Two more license vendors: Search & Filter Pro and Admin Columns Pro join the Licenses tab with the full loop: paste to activate, deactivate frees the seat, re-verify on demand, all through each vendor's own code. Search & Filter rides its REST controller and the free base plugin's own options store, and a rejected key can no longer clobber a working activation (their own screen would let it). Admin Columns Pro is admin-screen-gated by design, so Minn bootstraps its service container headless; its key-for-token swap (a successful activation trades your pasted key for an activation token) is handled and read back faithfully, lifetime licenses included.
  • Block this commenter: right-click a comment and Block commenter adds the author's email (or IP when the comment carries none) to core's disallowed list, so their future comments go straight to the trash. Core's own mechanism, no new storage: the entry is visible and editable under Settings → Comments, the confirm says exactly what will happen, and the toast's Undo removes exactly the line the block added. Offered to administrators, matching who may edit the disallowed list in wp-admin.

Improved

  • The editor sidebar's doors pack two-up: Settings, Page attributes, History, the custom-field panels and SEO now sit in a two-column grid instead of a full-width stack, roughly halving their vertical footprint on plugin-heavy posts. An odd count lets the last door span the width, summaries ellipsize inside the narrower cells, and the chevron gives its width back to the text. The Publish and Featured image cards keep their full rows.
  • Deleting a theme keeps the page still: the deleted theme's card fades out in place and the rest of the Themes tab stays exactly as it was (scroll position, sibling cards, screenshots untouched). The repaint through the loading screen is gone.
  • Comment rows open their post: the "on Post title" in every comment row is a door now. Clicking the title lands in the Minn editor (pages resolve too, not just posts), a quiet ↗ beside it views the post on the site landing right at that comment, and the row's right-click menu leads with Open post in editor and View post. Rows whose post cannot be resolved keep the plain label.

v0.19.0 - July 19, 2026

The storefront release. Orders stop being modal glimpses and become real pages with their own URLs, payments arrive by hand (a check in the mail is two clicks), refunds learn the order's own line items, and the Overview says out loud when the store needs you. Around the store: every site log in one viewer with a collapse-repeats mode, live posts carrying unsaved edits get a name (Modified) in the content list, Yes/No notices finally answer properly, and the post-lock story closes its last blind window with a server-side guard.

Added

  • Orders open as a full page: clicking an order now navigates to /minn-admin/orders/{id}, a real URL: linkable, refreshable and back-button friendly. The page hosts the full detail (customer and shipping, items, status, the Payment card with Record payment, refunds, WooCommerce emails, notes, subscriptions, and the customer's other orders) at full height with no inner scrollbox, the header keeps the status pill in view, and the Orders sidebar item stays lit. Every order reference navigates there: related orders on the page, a customer's order history, a subscription's parent and renewal orders, and a newly created order lands on its page too. The old modal survives as Quick view: a hover eye button on each row for one click, plus an entry on the row's right-click menu, with an Open full page action in its footer.
  • Receive payments by hand: the order modal gains a Payment card with the payment method (your enabled gateways plus a free-form Other), a transaction ID field, and a Record payment button on unpaid orders. A check arrives in the mail: pick Check payments, note the check number, record. Pending orders run through WooCommerce's own payment_complete (paid date, status move, stock and email hooks all fire); on-hold check orders, which WooCommerce's REST guard skips, get the paid stamp and processing status set explicitly, exactly as an admin would by hand. Method and transaction edits also ride the normal Save changes without touching the paid state.
  • The Overview knows when the store needs you: with WooCommerce active, a Store strip joins the dashboard under the stat cards listing the orders that need working today: awaiting payment, on hold, to fulfill and failed. Each count is a chip that lands on the Orders list pre-filtered to that status, a View orders button keeps the plain door, and an all-clear store says "All caught up" out loud instead of hiding the strip. Counts read from WooCommerce's own order counters, and the strip only renders for users who can manage orders.
  • The third state has a name: Modified. A published, scheduled or private post carrying unsaved edits (its newest autosave is newer than the version being served) now says so in the content list: an amber Modified chip beside the status, and a quiet Modified toolbar filter that shows only those posts. The state already existed, since Minn's status-aware autosave protects live posts by writing edits to revisions instead of the live copy; now it is named and filterable, backed by a minn_modified REST field and collection filter on every REST-visible post type. The editor's amber restore banner remains the way back in.
  • Site logs, all in one viewer: the System page's log viewer outgrew the single debug log. The Debug tools card now lists every log the site has: the WordPress debug log, the PHP error log when it is a separate file, and one source per WooCommerce log channel (gateway errors, transactional emails, fatal errors), each read through WooCommerce's own log controller. The full-screen viewer gains a source picker, and a collapse repeats mode that ignores digits when grouping, so ten thousand "Undefined index on line 47" repeats read as one line with a count. Clearing stays per source and only where it is safe (file logs you can write; WooCommerce retention stays on its own screen), plus a ⌘K "View site logs" command. Plugins and host mu-plugins can register their own sources through the new minn_admin_log_sources filter, documented in the author guide; Minn deliberately never guesses at web-server log paths.
  • More from this customer: the order modal lists the customer's other orders (status, total, age), found by account for registered customers and by billing email for guests. Click one to jump straight to it, or View all to open the Orders list pre-filtered to that customer.

Improved

  • Refunds grew up: the order Refund card lists the order's items with quantity steppers, so refunding two of the three mugs is two clicks. The amount computes itself (tax included) while staying hand-editable for shipping or goodwill refunds, and a Restock refunded items toggle rides WooCommerce's own restocking. The gateway checkbox names the real gateway ("Also refund via Stripe") and only appears when that gateway can actually push money back; check and manual orders say plainly that the record is manual and the money moves outside the site. Refund rows in the totals list gained when and who, plus a delete control that removes a mistaken refund record and restores the totals, with honest copy that money a gateway already sent is not pulled back. Underneath, a refund-state endpoint serves the accounting Minn could not get from wc/v3: per-line refunded quantities through WooCommerce's own bookkeeping, refunder names resolved server-side, and whether the order's gateway supports refunds.
  • The Playground demo feels like a lived-in site: the WordPress Playground blueprint now ships Koko Analytics with 65 days of seeded traffic (site totals, per-page stats and referrers, dated relative to whenever you launch it), so the Overview opens on a real Traffic chart with working day drill-downs. Code Snippets comes preloaded with three example snippets and User Switching joins the demo roster alongside Simple History, Redirection and the example adapter. Seeding runs through each plugin's own machinery (Koko's migration hook, Code Snippets' save API), and the demo continues to request the latest WordPress build Playground ships.
  • The payment picker mirrors wp-admin exactly: the method list is served by a Minn endpoint reading each gateway's computed title (the same call wp-admin's own dropdown renders and stores), so the options and the stored payment_method_title match the WooCommerce order screen byte-for-byte, even for gateways that generate their titles like Stripe. Saving without touching the method never rewrites the stored title (wp-admin's own rule).
  • The order modal's dropdowns are themed comboboxes: status, payment method and the WooCommerce email picker join the app's searchable combobox style; the last OS-drawn selects in the modal are gone.

Fixed

  • Activating a Performance Lab module no longer strands the list: turning a feature on installs and activates a real plugin, which can recycle the PHP worker and kill the very next request. The list reload after any action now replays once when its socket drops (the error card only paints if the replay also fails), and an action whose own reply dies after the server did the work proceeds to the reload instead of toasting a false failure. No more "Couldn't load this list" plus a manual refresh after activating a module.
  • Yes/No notices lost their Yes: Smash Balloon's "Are you enjoying the Instagram Feed Plugin?" notice showed fused text ("Plugin?YesNo") and only a No button, because its Yes is a literal button element the extractor never walked and notice text was flattened without element boundaries. Notice text now joins elements with spaces (and tidies punctuation), button elements join the CTA extraction in document order, and surfaced choice labels are stripped from the body by last whole-word occurrence, so a short "No" label can never eat part of the sentence. Buttons only surface when Minn can honestly answer them: a whitelisted handler, or a dismiss-shaped label. Both Instagram Feed choices now run the plugin's own consent handler from the panel, so Yes and No do exactly what they do in wp-admin.
  • A save racing a lock takeover is rejected by the server: the up-to-30-seconds between someone taking over a post and the losing session's next lock refresh used to be a blind window where the loser could still save and silently overwrite the taker's work. Minn's in-place saves now carry the post id in an X-Minn-Expect-Lock header, verified against the edit lock inside the save request itself; a save from an ousted session fails with a clear conflict error, nothing is written, and that session flips straight to the taken-over banner. Requests without the header (the block editor, other REST clients) behave exactly as before.
  • Taking a post lock back no longer risks silently reverting the other person's saves: when a lock changes hands, the winning session's copy could predate saves the other session made in the meantime, and the next save would quietly restore the stale copy. Regaining the lock now checks the server's modified stamp: a clean local copy adopts the newer saved version in place, and a copy with unsaved edits gets an amber banner naming who saved and offering Load theirs or keep working. Their work stays in revisions either way; choosing Load theirs also discards the local crash-net snapshot so the overwritten copy is never offered back.
  • The order modal no longer loses in-progress edits: its background fetches (emails, notes, related orders) re-render the modal as they land, and anything typed or picked in that window used to silently revert to saved values, with the save then persisting the reverted form. Edits now survive those refreshes, and focus returns to the field the rebuild stole it from.

v0.18.0 - July 18, 2026

The depth release. Plugin surfaces stop being flat lists: detail modals gain typed rows (status pills, code blocks, key-value tables and the real HTML email in a fully sandboxed preview), status cards spread across the whole mail, redirects and snippets families, and columns become sortable where a route supports it. The media library grows up in one cycle: folders from your folder plugin, an Unattached filter and month picker, an Attached-to jump, and replace-file in place through Enable Media Replace. The editor sidebar reaches events, job listings and podcast episodes with panels drawn live from each plugin's own schema, Gravity Forms feeds and FluentSMTP settings come inside, and four more providers join the families (SureForms, SureMails, Site Mailer, All-In-One Security). Underneath it all, a sequential full-suite runner drove all 171 suites green before this release and caught four real bugs, fixed below.

Added

  • Event details, editable in Minn: with The Events Calendar active, events gain an Event details panel in the editor sidebar: start and end, all-day, venue, organizer, cost and website. Venue and organizer are live search pickers over your existing TEC records, and every write goes through TEC's own save machinery, so durations, timezones and linked-post bookkeeping behave exactly as on its screens. Events with several organizers keep that field on TEC's screen rather than silently dropping any; recurrence and tickets stay in TEC too.
  • Plugin panels can offer search pickers: the editor-panel contract gains a suggest field type, an async picker that searches a route you provide as the user types (with a built-in None row for clearing). Documented in the author guide; the Events Calendar venue picker is the reference.
  • Job listings, editable in Minn: with WP Job Manager active, listings gain a Job listing panel in the editor sidebar covering location, the company fields, the application email or URL, salary, the remote, filled and featured flags, and the expiry date. The field list comes live from WP Job Manager's own schema (add-ons and site customizations included), and every write runs through its own per-field sanitizers.
  • PowerPress episodes too: with PowerPress active, plain posts gain the same Podcast episode panel for the default channel: media file URL, file size, duration, subtitle, and the Apple episode fields (title, number, season, type). Edits rebuild PowerPress's enclosure data carefully, so hosting, chapter and artwork details it stores alongside survive untouched, and clearing the URL removes the episode exactly like its own Remove control. Custom channels, artwork, explicit flags and chapters stay on the PowerPress metabox.
  • Podcast episodes, editable in Minn: with Seriously Simple Podcasting active, episodes already live in Minn's Content list and editor (they are a normal post type), and the editor sidebar gains a Podcast episode panel with the whole episode-detail estate: the media file URL, audio or video type, duration and file size, date recorded, the explicit and directory-block flags, and the iTunes fields. The panel reads its field list live from SSP's own schema (so a site with iTunes fields turned off sees fewer fields) and stores values exactly as SSP does; the cover-image uploader and Castos hosting sync stay on SSP's screen.
  • Gravity Forms feeds at a glance: with any feed add-on installed (Twilio, Mailchimp, Zapier, webhooks and the rest), the Forms surface gains a Feeds view listing every integration across your forms: which add-on, which form, on or off. Turn a feed on or off or delete it right there through Gravity Forms' own model; configuring a feed deep-links to the add-on's screen, where its credentials and builders live.
  • FluentSMTP settings, without the wizard: the FluentSMTP Email surface gains a Settings view for the choices that actually change day to day: the default and fallback connection (picked from your configured connections; credentials never leave FluentSMTP), email logging, log retention, and email simulation for staging sites (locked when a wp-config constant forces it). Everything reads and writes through FluentSMTP's own settings model; setting up a new connection stays in its wizard.
  • Media folders, from your folder plugin: with FileBird, Real Media Library or Folders by Premio active, the Media view gains a folder picker listing your folders (with counts, children indented, plus each plugin's own no-folder view) and filters the library to the picked folder while search, type tabs and pagination keep working. Everything reads through each plugin's own model or API, so FileBird's per-user folders mode is honored and counts match their screens; organizing stays in the plugin's UI. Other folder plugins can join through the new minn_admin_media_folders provider filter, documented in the author guide; very large folders honestly show their newest 500 files and say so.
  • Move to folder: select files in the media library and the bulk bar offers a folder picker and a Move button (with "no folder" as a real destination). The move runs through the folder plugin's own assign machinery, so its hooks, counters and per-user scoping all apply; providers opt in with a single move callable on the same filter.
  • The media buttons work with more plugins: the SVG filter tab and detail note now come from Safe SVG or SVG Support (the note names the plugin, and claims sanitization only where it is certain), and the ↻ Thumbnails button works through Force Regenerate Thumbnails when Regenerate Thumbnails is not installed, calling FRT's own handler so its delete-stale-files behavior applies exactly as on its Tools screen.
  • Media filters that answer the two daily questions: an Unattached filter shows the files no post or page claims (core's own parent query, ready for a cleanup pass), and a month picker lists exactly the months that hold uploads, with counts, so "that screenshot from May" is two clicks. Both keep the toolbar painted while the list reloads, and the media toolbar moves to the same two-row layout as Content.
  • Every file says where it lives: the media detail modal gains an Attached to row naming the post or page the file was uploaded to, and clicking it drops you straight into that post's editor. Files nothing claims read Unattached, plainly.
  • Replace a file in place: with Enable Media Replace active, the media detail modal gains a ⇅ Replace file button. The new upload goes through EMR's own replace machinery: the old file and its thumbnails are removed, the new file lands under the same name and URL (so every post, theme and hotlink reference keeps working), metadata and thumbnails are rebuilt, and EMR's hooks fire for other plugins. Minn enforces the honest constraint of in-place replacement (the new file must be the same type); renaming or moving the file stays on EMR's own screen. Capabilities mirror EMR exactly, including a wp-config EMR_CAPABILITY override.
  • Status cards across the whole redirects family: Safe Redirect Manager (rules, status-code mix, regex count), Simple 301 Redirects (rule count and the wildcard toggle) and 301 Redirects by WebFactory (rules, lifetime hits, top redirect, 404 log size) join Redirection with an at-a-glance card, each read from the plugin's own storage.
  • Status cards across the whole snippets family: WPCode, FluentSnippets, Custom CSS & JS and Header Footer Code Manager each open with the same at-a-glance card as Code Snippets: active and inactive counts plus each store's own facts (running types or languages, the last change, FluentSnippets' file-based storage note).
  • Code Snippets status card: the Snippets surface opens with active, inactive and trashed counts, the scopes currently running, the most recent change, and a warning row whenever safe mode is armed (safe mode means nothing executes, which deserves saying out loud).
  • SureForms entries join the Forms surface: submissions read from SureForms' own table, with per-form tabs, unread/read/trash filtering and bulk status changes, search, an entry contact card, and a status card of unread and total counts.
  • Two more email loggers: SureMails and Site Mailer: both join the Email family reading their own free log tables, with sent/failed tabs, search, single and bulk delete, a status card with a 14-day chart, and the sections detail (status pill, the real HTML body in the sandboxed preview). Timestamps are normalized to UTC no matter what timezone the database runs in.
  • All-In-One Security joins the Activity Log: its audit feed reads from AIOS's own log table as a fifth activity-log provider, with level tabs (warnings, errors, info), search, per-event detail (the JSON context flattened into readable fields) and a status card counting 24-hour, 7-day and all-time events plus recent warnings.
  • Sortable columns on plugin surfaces: a collection can declare sortQuery (an orderby/direction template) and mark columns with the sort token its route understands. Marked headers become clickable: numeric and date columns start descending, everything else ascending, and a repeat click flips. The Redirects surface is the first consumer, sorting by source, hits and last hit through Redirection's own API.
  • Redirection status card: the Redirects surface opens with rule counts, all-time hits, the top redirect, served and 404 counts for the log window, and a stacked 14-day chart of redirects served over 404s, all read from Redirection's own tables.
  • The whole mail family opens rich detail: FluentSMTP, Post SMTP and WP Mail Logging log details moved to the new sections layout alongside Gravity SMTP: a status pill, the real HTML email body in the sandboxed preview (plain-text bodies as a code block), and each store's own extras (FluentSMTP's provider-reply peek, Post SMTP's failure text and suggested fix, WP Mail Logging's raw headers). The flat detail routes stay for API consumers.
  • Detail row types for plugin surfaces: a sectionsRoute response row can now declare type: pill (the shared status vocabulary), code (escaped monospace block), html-preview (your HTML in a fully sandboxed iframe, no scripts, opaque origin) or kv-table (a two-column table from an object map or pair list), alongside the existing url and email link rows. Values stay escaped everywhere; the sandbox is the one place plugin markup renders. Gravity SMTP's log detail is the first consumer: delivery facts with a status pill, the real HTML email body rendered safely, and the stored headers as a table.

Improved

  • The System theme glyph is a half-circle now: the theme toggle's System state wore a monitor icon, which read as "view the site" rather than "follow the OS". It wears the conventional half-filled circle instead; Light and Dark keep the sun and moon.
  • A full-suite runner ships with the repo: tests/run-all.sh runs all 171 Playwright suites sequentially with settle guards, a one-retry rule for environment noise, per-suite logs and resume support, so a release pre-flight (or an overnight run) is one command.

Fixed

  • The block picker no longer waits on the slowest design library: it used to hold the whole dialog on every design and pattern source before rendering anything, so one slow or unreachable CDN left it stuck on the loading screen. It opens instantly with the basics now, and each design library and pattern group fills in as its source answers; a dead source just never arrives.
  • The Overview traffic chart dropped today's visitors before noon UTC: the chart bucketed provider days against a noon-UTC anchor, so for half of every day the current day computed as "in the future" and vanished from the chart (and a bar's drill-down could land on the wrong day). Days are bucketed by calendar distance now, in the site's timezone.
  • Gravity SMTP's Resend button vanished from the log detail: the new sections-based detail no longer feeds the full event back to the modal, and the list route never carried the resend permission its when-gate read, so the button silently disappeared. The list route carries it now.
  • A failed license activation could eat the typed key: the Licenses tab was the one list still missing the soft-reload guard, so a stray re-render during the tab's refresh window could detach the activation form mid-flight, typed key and all. It keeps the form (and the key) through the refresh now.

v0.17.0 - July 17, 2026

The boundaries release. Minn's integration story grows teeth: placement and count budgets are enforced rather than requested, every off-site link a plugin supplies wears the mark, the descriptor vocabulary is frozen by a kitchen-sink contract suite, and anything you don't want is one right-click away from hidden, restorable from Your profile. Which is now a real page: account, public profile, appearance, per-user language with automatic pack installs, the front-end toolbar preference, AI access and sessions as calm cards. The command palette searches what you've written, the commerce views and menu items gain right-click menus, the author guide is rebuilt around first contact with a copyable example plugin, and the last native selects and checkboxes in Settings and the structure dialogs became themed controls.

Added

  • ⌘K finds your content: the command palette now searches what you've written, not just what Minn can do. Type anything and your posts, pages and custom post types appear under the command matches (published content plus your drafts and scheduled posts), and Enter drops you straight into the Minn editor. Same arrow-key and click behavior as commands, debounced against core's search API with the usual field allowlist (lists never render content), and commands always stay first.
  • Hide any integration for you: right-click a plugin surface's sidebar row, a plugin editor panel's door, or a plugin group's heading in the block picker and choose Hide for you. Design libraries hide individually; a slash namespace hides everywhere it feeds the editor menus (auto-insertable blocks, insert templates, block patterns and namespaced commands go together, while inspector forms stay so existing blocks remain editable). Hidden integrations leave the boot payload entirely (the sidebar, ⌘K palette, routes, block picker and slash menu never see them), survive reloads, and restore from Your profile → Hidden for you or the Undo toast. The choice is per user; plugin re-registration does not undo it, and there is no API for a plugin to detect or resist it. Core views, core editor doors and the picker's Basics are not hideable.
  • Attention budgets: placement and count limits on plugin integrations are now enforced, not asked. The Workspace nav group requires an inbox-shaped surface (a time-ordered collection); anything else claiming it lands under Tools with a note on the Integrations card. One plugin holds at most 3 nav slots: past that, its surfaces collapse into a single nav item and a single ⌘K palette row using the familiar provider switcher. One namespace holds at most 3 entries in the default / slash menu, with overflow demoted to search-only (still one keystroke away, never dropped; the block picker always shows everything). Minn's own bundled adapters are exempt from the nav budget since each registers only while its subject plugin is active.
  • External links are always marked: every link a plugin's descriptor supplies (row and detail actions, status-card actions, setup links, context-menu entries) opens in a new tab, and any link that leaves the site now renders with the ↗ affordance automatically. Minn adds the mark at render time; a descriptor cannot make an off-site link look like an app action, and same-site wp-admin deep links stay unmarked. Off-site hrefs carried in a descriptor are also listed per surface on the Integrations card, attributed to the plugin that registered them (informational, never a contract problem).
  • The contract suite: the descriptor vocabulary is now frozen by test. A doc-lockstep check fails the suite if any key in the validator's vocabulary constants is missing from the author guide, and a kitchen-sink fixture surface declares the entire documented collection vocabulary at once (every column format, every action key, tabs, filter, bulk, create with defaults, inline edit with preserve, manage and extra views, status card, item-scoped settings) and is driven end to end with server-state verification. The same fixture validating with zero problems on the Integrations card proves the full vocabulary is contract-clean. The WordPress Playground demo also boots the shim tutorial's example plugin preactivated, so a working instance of the API is one click away.
  • The shim tutorial and a copyable example plugin: docs/shim-tutorial.md walks a custom-table plugin into a full Minn surface (REST shim, descriptor, status card, actions), and docs/examples/minn-example-adapter/ is the finished code as a real working plugin. Minn's own test suite activates the example and drives it end to end, so the tutorial can never drift from the contract.
  • Your profile is a full page: the self-profile outgrew its modal and lives at /minn-admin/profile now, with Account (name, email, role, language, password), Public profile (first and last name, website, bio and the Gravatar-sourced picture, the fields author boxes and archives read), Appearance (color schemes, theme, and the front-end toolbar preference), Hidden for you, AI Access and Sessions as proper cards. The avatar, the ⌘K entry and your own row on Users all land there; the modal stays for adding users and editing other people, where the short form is right.
  • Per-user language, with automatic installs: the Language picker offers every installed locale plus the full downloadable catalog (for admins who can install languages), exactly like core's Site Language dropdown. Picking a language that is not installed yet downloads its pack on save through minn-admin/v1/me/language; Site default remains the first option, and the picker reads your raw preference, not the effective fallback.
  • Show toolbar when viewing the site: core's per-user admin-bar preference joins the Appearance card as an instant-save switch, exposed over REST via registered user meta with core's own true/false storage.
  • Right-click menus on Orders, Products, Customers and Menus: the context-menu pattern from Content, Media and Comments reaches the commerce views and menu items. Orders offer the common status moves (processing, completed, on hold) without opening the modal; products toggle stock and publish state in place (managed-stock products keep stock edits in the modal, where quantity lives); customers offer email, a pre-filtered jump to their orders, and the wp-admin user screen; menu rows expose their own move, indent and remove controls plus the inline label editor.

Improved

  • The author guide, restructured for first contact: the quick start now opens the doc (the 19-hook wall moved to a Hook reference section), with new sections for testing your integration, capability patterns (including the adapter-side gating precedent the bundled adapters use), the canonical icon list (66 names; unknown names render empty), building with an AI agent, and Integration etiquette: the whole enforcement story in one place (what the validator blocks or degrades, that rendering is Minn's, what users can hide, and that labels are for naming, not marketing). Every primitive now has a screenshot beside its section (surface list, status card, detail modal, contact-card entry, setup gate, settings view, editor panel doors and modal, slash namespace entries), captured from the live app with the shim tutorial's own Campfire example as the subject; minnadmin.com's guide modal renders them too. The run-on actions and filter table cells became real sections, manage vs views is differentiated, group's two honored values are stated, newer keys carry since-version notes, and required keys are named up front (label, collection.route, columns). The stale extension-api.md proposal (whose example used keys that no longer exist) is deleted.
  • A first-class Forms provider recipe: the author guide gains a worked section for forms plugins specifically: per-form dynamic tabs paired with {tab} routes, how entry-summary picks its list line (and the summary override), the contact-card entry detail's hero and body heuristics, the Entries/Forms manage shape, family: 'forms' coexistence semantics, and the honest href export pattern. Plus the previously undocumented detail.labels response contract, DELETE-method actions, column sortability (fixed by your route, stated plainly), WP_Error handling on create, and what an older Minn does with newer descriptor keys.
  • Post Types and Taxonomies dialogs: the visibility, supports, taxonomy and attach-to checkboxes are proper toggle switches now (the whole row is the click target), and the "Store definition in" picker is the themed combobox instead of a native select. Locked core and code-registered definitions render the same switches, dimmed and inert.
  • Calmer plugin-surface headers: the status card puts its action buttons beside the stat rows instead of alone at the bottom, and a chart window with nothing sent or failed collapses to a one-line note instead of 88 pixels of empty bars (Gravity SMTP in test mode sandboxes everything, so its Sent/Failed chart was pure dead space). The second row of filter pills under a view switcher (Log's All/Sent/Failed, Settings tabs) drops the boxed strip for the quiet text style, so each screen keeps one boxed pill row.

Fixed

  • A dropped reply no longer wipes a soft-reloading list: a tab, filter or search request that dies mid-flight (a PHP worker recycle, flaky network) used to replace the whole view with the error card, toolbar included. The chrome now stays painted, the dim clears, and an error toast reports it; the next click simply retries. Chrome-less first paints still show the error card.
  • The shield icon rendered blank: three bundled adapters (Wordfence, Solid Security, Limit Login Attempts) declared it but the icon map never carried it.
  • Content's Trash control floated mid-toolbar: the aux tab strip inherited the stretching flex rule meant for the type tabs, leaving a dim "Trash" word stranded in the middle of the row. It pins to the toolbar's right edge now, wears the trash icon, and sits a step brighter than the quiet filter tabs.
  • Settings kept three native selects: the homepage-displays picker, the default post format and the permalink-structure preset were the last OS-drawn dropdowns on the Settings page. All three are the themed searchable combobox now, with the homepage mode flip still revealing the page pickers and the permalink preset staying in two-way sync with the custom-structure field.

v0.16.0 - July 16, 2026

The personalization and polish cycle. Minn now looks and behaves per user: named color schemes for light and dark (or a fully custom palette) picked on Your profile, and preferring Minn as the default admin becomes an opt-in per-user choice. Lists calm down across the app: tab, filter, and search changes keep toolbars painted and dim in place instead of flashing a Loading screen, on Content, Media, the commerce views, and plugin surfaces alike. The editor gets quieter and deeper at once: secondary meta tucks behind door rows, revisions open with an activity heatmap, the schedule calendar shows what is already planned, and long titles finally wrap. Licenses keep growing with Yoast SEO Premium and the Smash Balloon family, activity logs gain status cards, and updating a single plugin or theme no longer wipes every other pending offer.

Added

  • Yoast SEO Premium license: Extensions → Licenses gains a Yoast SEO Premium row. Subscription state comes from free Yoast SEO's MyYoast site info (WPSEO_Addon_Manager); there is no paste-a-key path. Activate ↗ opens Yoast's Licenses page, and Verify refreshes the MyYoast cache.
  • Smash Balloon licenses: Extensions → Licenses gains dedicated rows for Instagram Feed Pro, Custom Facebook Feed Pro, YouTube Feed Pro, Custom Twitter Feeds Pro, Social Wall, Reviews Feed Pro, TikTok Feeds Pro and Feed Analytics Pro. Paste-to-activate, deactivate and re-verify go through Smash Balloon's own EDD store (smashballoon.com); an All Plugins multi-product key activates each product with that product's own download name.
  • Per-user color schemes: how Minn looks is now a per-user preference on Your profile. Pick a named scheme for light and dark, or build a Custom scheme with per-slot color pickers (13 surface and brand tokens). Preferences live in minn_admin_appearance user meta via minn-admin/v1/me/appearance, paint FOUC-free from the pre-paint script, and scheme flips apply instantly with the save debounced in the background. Theme mode (System / Light / Dark) joins the profile beside the schemes, sharing the topbar control's preference. Legacy accent-only choices migrate; status colors stay fixed.
  • Open in new tab on the link popover: a switch on the editor's link popover sets target="_blank" (with noreferrer noopener) on Apply; links that already open in a new tab seed the switch on.
  • Schedule calendar shows what's already planned: in the date picker, days that already have published or scheduled items of the same type get a tint and an under-dot, with a floating list of titles on hover and a legend when any day is marked. Months soft-load as you page through the grid.

Fixed

  • Single plugin update cleared every other update notice: Plugin_Upgrader runs wp_clean_plugins_cache, which deletes the whole update_plugins transient. Updating one plugin (e.g. Jetpack from Notifications) then wiped every remaining plugin offer from the panel and Extensions badges. Minn now snapshots pending offers before the upgrade and restores every file that was not updated.
  • Single theme update cleared every other theme offer: same trap for Theme_Upgrader / wp_clean_themes_cache / update_themes. Snapshot and restore the other stylesheets after a single theme upgrade.
  • Extensions list empty after a notification-panel plugin update: finishing the last plugin update while the Updates filter was active (or left sticky from earlier) hid the Updates pill and left a blank “No updates plugins” page even though All still showed full counts. When no plugin/theme updates remain, Minn snaps back to All, keeps the active filter pill visible at zero, and uses clearer empty copy.
  • Connectors after Install & activate: installing a provider plugin (e.g. OpenAI) no longer leaves Settings → Connectors on “Connectors couldn’t be loaded” when the PHP worker recycles mid-response. Minn waits for REST, retries the connectors fetch, and offers an in-panel Retry if a load still fails. A dropped install reply after a successful package install is treated as success and reloads the list the same way.

Improved

  • Users list column sort: Name, Email, and Registered are sortable headers (server-side via wp/v2/users orderby / order). Click flips direction; a new column uses a sensible default (A→Z for name/email, newest first for registered). Role is not sortable (WordPress has no roles orderby).
  • Revision heatmap: the All revisions dialog opens with a GitHub-style activity grid (activity window capped ~3–6 months so empty years don’t dominate). Click a day to filter the list to that day; click again or Show all to clear.
  • Rank Math social thumbnail: when Rank Math is the active SEO provider, the SEO panel gains a Social thumbnail image field (Facebook OG image; Twitter inherits via Rank Math’s own flag). Set / replace / remove through the media picker; values write rank_math_facebook_image + _id.
  • Settings door summary omits Uncategorized: only real category picks appear on the Settings door one-liner.
  • Sticky moved to Settings: “Stick to the top of the blog” leaves the Publish card (still hidden under password visibility) and lives in the Settings modal with discussion.
  • Editor sidebar doors: secondary editor meta (Settings, Page attributes, History, Custom fields, SEO, …) is a quiet door row with a one-line summary that opens a large modal. Publish, Featured image, and Outline stay on the rail so the write path stays one glance. Same fields, dirty flags, and autosave as before — no second save button in the modal.
  • Content list thumbnails: posts and pages with a featured image show a small thumb in the content list (type icon stays when none is set). Uses core REST _embed=wp:featuredmedia with the existing _fields allowlist, so lists still never run the_content.
  • Content list type chip: on the All tab, each row shows a quiet Post / Page / CPT chip under the title (same line as the slug and builder chip). Not a full column: single-type tabs already name the type in the filter, and thumbs had hidden the ¶/file glyph.
  • Gravity SMTP bulk log delete: the Email log (the mail family reference) gains single-row and bulk Delete, through Gravity SMTP's own Event_Model::delete and gated on its DELETE_EMAIL_LOG capability. Permanent, no trash; same shape FluentSMTP and Post SMTP already had.
  • Activity Log status cards: Simple History, WP Activity Log, Stream and Aryo each gain a status strip above the list (events in the last 24 hours and 7 days, all-time total, last event, plus a family-specific mix: severity, high+critical, top connector, or top action). Matches the daily-ops depth Solid Security, Limit Login Attempts and Wordfence already had. Open ↗ deep-links to each plugin's own screen.
  • Extensions cards drop the ⋯ button: plugin and theme cards open their actions menu only via right-click (or long-press). The on-card ⋯ was the same menu and just cluttered the foot.
  • Default admin is per-user and opt-in: "Prefer Minn Admin as the default admin" is a profile preference now, off unless you turn it on (it is no longer seeded from the legacy site option). When on, login lands in Minn and edit links open the Minn editor; wp-admin lists and screens keep their classic Edit links either way, with only the admin bar's edit entry retargeted. The admin bar entry always reads "Minn Admin".
  • Soft-reload keeps list chrome painted: Content, Comments, Orders, Subscriptions, Products, Coupons, Customers, Media, and surface lists (Gravity Forms and friends) share one soft-reload path. Tab, filter, and search changes keep the toolbar and tabs painted and dim the list body instead of replacing the whole view with "Loading…". First visits to Extensions Themes / Licenses, Menus, and Structure keep the tab strip too, and stale responses after a fast tab change are ignored.
  • Long editor titles wrap: the title is an auto-sizing textarea, so long titles wrap onto multiple lines instead of clipping. Enter still moves into the body and never inserts a newline.
  • Users: ID and session filter: the list shows a sortable ID column (the edit dialog shows the ID too) and filters by session status (All / Active / Expired / Never signed in) through minn-admin/v1/users.
  • Editor switches: Discussion, Stickiness, and Public preview checkboxes are now left-aligned switches.
  • Media toolbar drops the SVG pill: the SVG filter tab already signals Safe SVG is active, so the green toolbar badge is gone (the sanitization note stays on media detail).

v0.15.0 - July 15, 2026

The library and daily-ops cycle. Performance settings join a provider family beside Perfmatters, Add plugin opens a marketing-style catalog, Meta Box and Pods land in the editor sidebar next to ACF, WooCommerce Subscriptions gets its own Workspace surface, and Extensions finally feels like a real package manager: card menus, clearer hub links, resilient Update all, and per-row Update on notification offers. Notices and mail keep catching up to real plugins: clickable Allow / No Thanks, ThemeIsle dismiss in-panel, Post SMTP search and delete, and a Fluent Forms suite that closes the last forms-family coverage gap.

Added

  • Performance family pack: the thin Performance card grows three popular peers alongside Perfmatters, sharing one Tools nav item with a provider switcher. Autoptimize maps its daily JS / CSS / HTML / CDN / Misc options as a settings-only surface (Critical CSS, Extra and Image stay in Autoptimize; Clear site cache still purges its cache). Asset CleanUp maps global minify/combine, head cleanup, Google Fonts and test-mode toggles the same way (the page-level CSS/JS unload manager stays in Asset CleanUp). Performance Lab lists the WordPress Performance Team standalone features with Activate (through its own install helper) and Deactivate, plus a status card.
  • Add plugin catalog: the Add plugin dialog opens on a marketing-style grid of popular plugins by category (SEO, Forms, Backup, Performance, Dev tools, and more) instead of flat search chips. Click a chip to install from WordPress.org or activate if already present; Disembark installs from its latest GitHub release. Hover a chip for a tip with icon, author, active installs and short description (wordpress.org info, cached 12h; GitHub-only plugins use a local blurb). Free-text search still hits the directory, with a one-click return to the catalog.
  • Meta Box editor panel: simple Meta Box fields (text, textarea, number, range, email, url, select, radio, checkbox, switch) appear in the editor sidebar as Custom fields · Meta Box, with values on a dedicated minn_meta_box REST field written through rwmb_set_meta. Cloneable and advanced fields count as locked with a wp-admin link (ACF-style).
  • Pods editor panel: simple Pods fields on extended post types (text, paragraph, number, email, website, single custom-simple pick, boolean) appear as Custom fields · Pods, with values on a dedicated minn_pods REST field written through pods()->save(). File, relationship, multi-pick and other advanced types count as locked with a wp-admin link.
  • Traffic day drill-down for Burst and Independent Analytics: the Overview Traffic bar modal now answers from Burst Statistics (burst_statistics pages + burst_sessions referrers) and Independent Analytics (views × resources + session referrers), joining Koko and WP Statistics on minn_admin_traffic_day.
  • Safe SVG media affordance: when Safe SVG is active, Media gains an SVG filter tab, an SVG on badge, and a detail note that uploads are sanitized by Safe SVG. Sanitization stays the plugin's job; Minn only surfaces that SVG uploads are allowed.
  • WooCommerce Subscriptions: when the extension is active, Workspace gains Subscriptions (status tabs, search, next payment, billing period, detail modal with status save through wc/v3/subscriptions, related orders, deep link). Order modals list related subscriptions and open them in place. The shop_subscription CPT stays fenced out of Content.
  • Extensions card menus (plugins and themes): right-click, long-press, or the button on a plugin or theme card for Activate / Deactivate (or Activate theme), Update when an offer is pending, Delete when allowed, plus Links (Open on WordPress.org / Open on GitHub when the URL is on those hosts, otherwise plugin/theme website and author) and Copy plugin file / stylesheet. Theme cards also link the screenshot and author to the theme hub when known. Verbs share the same handlers as the on-card controls so the menu cannot drift.
  • Update buttons on update notifications: each plugin, theme, or WordPress core update row in the Notifications panel has its own Update → version button (same serial queue and labels as Extensions), so you can apply one offer without Update everything.

Fixed

  • Otter / ThemeIsle “No, thanks.” dismisses in-panel: review nags that link to wp-admin/index.php?nid=…&tsdk_dismiss_nonce=… (and similar admin dismiss URLs) run as background actions instead of opening wp-admin in a new tab. External review CTAs (wordpress.org) still open in a new tab.
  • Notification panel keeps scroll on mark-read: clicking a notice to clear its unread dot no longer jumps the list back to the top.

Improved

  • Fluent Forms suite: Playwright coverage for the Fluent Forms entries surface (form tabs, Received/Spam/Trash filters, search, labeled detail + mark-read on open, trash and permanent delete, Forms manage view). Closes the last forms-family suite gap for an adapter that already had full depth.
  • Notice “No, Thanks” / “Allow” buttons work: telemetry and opt-in nags that only use href="#" buttons (Everest Forms contribute notice, and the same shape) show as real action buttons in the Notifications panel instead of dead text. No, Thanks runs the plugin’s dismiss path (whitelist) so the nag does not bounce back; Hide still works for everything else.
  • Post SMTP email log: search (subject / to / from) and permanent single + bulk delete on the log, matching FluentSMTP and WP Mail Logging. Session transcripts stay out of the surface.
  • Content bulk status is a themed combobox: the bulk bar's Set status… control (and Products' status / stock pickers) uses the same searchable autocomplete as Users bulk role, instead of a native OS <select>.
  • Update all feedback on Extensions cards: Update all queues each pending plugin through the same one-at-a-time path as a single Update click, so cards show Queued… then Updating… (with a highlight on the active card) and the toolbar button reads Updating… (N) until the queue drains, instead of a silent bulk request with only a toast.
  • Plugin update queue survives worker recycles: after each upgrade (and on "Failed to fetch" / connection refused) Minn waits for REST to answer again before the next card, retries a dropped upgrade, and treats a vanished update offer as success when the reply was lost mid-upgrade. Stops a multi-update run from dying after the first successful package swap on FrankenPHP.
  • Subscriptions polish: clearer empty state; parent order callout and open action; View customer from the subscription modal; customer detail gains a Subscriptions strip (and All subscriptions) when WooCommerce Subscriptions is active. Dogfooded on WooCommerce Subscriptions 9.0.1 (same wc/v3/subscriptions contract; detail also shows manual renewal and suspension count when present).

v0.14.0 - July 14, 2026

The commerce release. WooCommerce day-to-day work lands in Minn: Products, Coupons, Customers, order create and deep order management (notes, refunds, resend and compose email, pay URL), plus an Orders Analytics view with long-range revenue and top products. Diagnostics collapse four tools into one family (Scrutoscope, WP Crontrol, Transients Manager, Rewrite Rules Inspector). The editor grows shareable draft links through Public Post Preview, a full revisions browser, paste-a-URL-to-link and Select All that finally includes island block text. FluentSMTP catches up with search and log delete.

Added

  • Products surface: WooCommerce catalog work lives at /minn-admin/products (Workspace nav + ⌘K), not in the Content writing editor. List with status tabs (Published / Draft / Private / Pending), stock filters (In stock / Out / On backorder / Low stock via WooCommerce Analytics), search by name, SKU or exact ID, bulk status and stock updates, and a wide detail modal for the daily fields: name, SKU, status, catalog visibility, regular/sale price, stock tracking and status, and short description. Variable and grouped products show price/stock as read-only with an honest note; full gallery, variations and long description stay one click away via Edit in WooCommerce / View product. The product CPT is fenced out of Content type tabs so opening a product never drops into the Minn post editor by mistake.
  • Coupons surface: promo codes at /minn-admin/coupons (Workspace + ⌘K). List with status tabs, search by code or ID, create and edit daily fields (code, discount type, amount, usage limits, per-user limit, minimum spend, expiry, individual use, free shipping), delete, and Edit in WooCommerce. The shop_coupon CPT is fenced out of Content.
  • Customers surface: registered WooCommerce customers at /minn-admin/customers (Workspace + ⌘K). Search by name, email or ID; detail modal shows profile, billing and recent orders (click through to the order modal).
  • Create product / create order: Add product on Products creates a simple product (name, price, SKU, status) then opens the edit modal. New order on Orders builds a processing (or pending/on-hold) order with billing details and one line item via product search.
  • Orders Analytics view: pill switcher on Orders (Orders | Analytics). Revenue chart, gross sales / net revenue / orders / items cards, and top products from WooCommerce Analytics (wc-analytics reports). Ranges: 7d / 30d / 90d / 1y / All, with monthly bars on long windows.
  • Orders management depth: the order modal loads the full WooCommerce order and covers the day-to-day fixes people still bounced to wp-admin for. Edit billing (name, email, phone, address), shipping address, customer note and status in one save; issue a partial or full refund with optional payment-gateway refund; copy the customer payment URL; resend any order-scoped WooCommerce email (invoice, processing, completed, and the rest) through WC's own mailer; and Send email… opens a Users-style compose form to the billing address with a prefilled subject/body and an order pay-or-view button in the HTML email. Notes are recorded on the order. Deep link targets the single order edit screen. The list gains a search box (order ID, number, customer name, email and the rest of WooCommerce's order search).
  • Order notes: the order modal loads the WooCommerce notes timeline (private and customer-visible), and staff can add a new note with a "visible to customer" toggle without leaving Minn.
  • Diagnostics family (Scrutoscope, WP Crontrol, Transients Manager, Rewrite Rules Inspector): Dev tools share one Tools nav item with a provider switcher instead of a top-level entry per plugin. Scrutoscope lists performance profiles (Pinned / Session / Background), detail sections from its own /profile/{id} (sources, queries, HTTP, milestones), a status card, an attribution Cron view, and delete through its Storage. WP Crontrol is the actionable cron manager (overdue / paused / recurring / one-off, run-now, pause/resume, delete via Crontrol\Event\*). Transients Manager lists options-table transients with search and Expired / Persistent / Site-wide filters, delete and bulk delete through core delete_transient, and a Delete expired status action through their own purge; serialized values stay opaque (type + size only). Rewrite Rules Inspector lists registered rules with source attribution (Missing / Core / Posts / Pages / Other tabs, search by text or path), flushes soft rewrite rules the same way their tool does, and tests a path against the rule set with a first-match toast. Capture settings, PHP/URL cron authoring, full transient edit, and the full RRI screen stay deep-linked. Complements the Query Monitor chip and System's cron / expired-transients health rows.
  • Public Post Preview adapter: when Public Post Preview is active, the editor Publish card gains a Public preview link toggle (enable copies the share URL; disable revokes it), and the content row menu offers Copy public preview link (enables if needed). Links and expiry stay the plugin's own nonces and Reading setting; Minn only reads/writes their post-id list and calls get_preview_link.
  • FluentSMTP search and delete: the Email surface for FluentSMTP gains subject/from/to search (the same columns their Logger searches) plus permanent single and bulk delete through Logger::delete, with a prefix-scoped SQL fallback when the class is unavailable.
  • View all revisions: the editor History card still shows the latest few versions, and when more exist (the live total from wp/v2/…/revisions) a View all revisions (N) control opens a dialog of every revision with absolute timestamps. Pick a row to open the existing side-by-side diff; ←/→ then walks the full list.

Improved

  • Copy includes island blocks: Select All (or any selection that spans a dynamic/custom block island) now puts the island's visible content on the clipboard with the surrounding prose. Browsers skip contenteditable=false islands by default, so the card text used to vanish from ⌘C; copy and cut rebuild text/plain and text/html from the selected top-level blocks (preview HTML for islands, plus their Gutenberg raw under text/x-minn-blocks).
  • Paste a URL over selected text to hyperlink it: in the editor, selecting words and pasting a URL (or a browser-copied link) wraps the selection in a link and keeps the original words, instead of replacing them with the URL string. Code blocks and islands still paste as plain text.
  • Orders Analytics chrome stays put while ranges load: changing the range keeps the Orders|Analytics switcher, range tabs and stat card headers on screen (values show … until the new data lands) instead of blanking to a lone "Loading…" line. Top products request extended_info so names show instead of bare IDs.

Fixed

  • Orders status tabs missed pending / cancelled / failed: the list tabs cover the full WooCommerce set (All, Processing, Completed, On hold, Pending, Cancelled, Refunded, Failed) so older failed or pending orders are not hidden behind an incomplete filter strip.
  • Coupons nav when WooCommerce coupons are disabled: if Enable coupons is off, shop_coupon is not registered and wc/v3/coupons always returns "Sorry, you cannot list resources." Minn now only offers Coupons when WC has coupons enabled and the post type exists (and shows a clear settings link if the route is hit anyway).

v0.13.0 - July 13, 2026

The depth release. Surfaces grow a third list view and item-scoped settings, proven end to end on Gravity Forms (per-form settings drawn from its own schema, plus a Notifications view) and Gravity SMTP (Debug log, Routing, status-card charts). Three more form plugins join the family (Forminator, Formidable, Everest Forms), backups expand to WPvivid, BackWPup and All-in-One WP Migration, snippets take Simple Custom CSS and JS and Header Footer Code Manager, and Clear site cache covers five more providers. Older adapters catch up to the new primitives (status filters, bulk, charts, tabs) across mail, forms, redirects and activity log. The editor closes Horizon 2 with writing stats and a slash-command extension point, picks up IME, mobile Safari and accessibility passes, and surface/Content toolbars finally stop fighting for one row. Theme defaults to System.

Added

  • Editor slash-command extension filter: plugins register free-form / commands through minn_admin_editor_commands (boilerplate HTML, island templates, or an async REST route that returns either), with keywords, namespace badges and optional search-only entries so the default menu stays curated. Same commands appear in the block picker under {plugin} · commands. Pure descriptors; no third-party JS in the Minn document. Documented in docs/for-plugin-authors.md.
  • Writing stats on the editor pill: total words and reading time grow a session delta (words written since you first edited this open) and an optional word goal. Click the pill to set or clear a goal; it turns green when you hit it. Goal is global and sticks across posts.
  • Traffic day drill-down: clicking a bar on the Overview Traffic chart opens a modal of that day's (or week's) top pages and referrers, the same click-for-detail pattern the Activity chart already had. Providers: Koko Analytics (local post_stats / paths / referrer tables) and WP Statistics (statistics_pages + visitor referrers). Other adapters join through the new minn_admin_traffic_day filter. The Visitors card now always names pageviews alongside the period delta. Documented in docs/for-plugin-authors.md.
  • Status-card charts: a surface status payload may include a chart series (title, daily points, optional dual primary/secondary values) and Minn draws Overview-style bars with a hover tip above the list. Gravity SMTP's Email status card is the first consumer: a 14-day sent/failed chart built from its own events table. Documented in docs/for-plugin-authors.md.
  • Surfaces can declare any number of list views: beyond the main collection and the Manage slot, a surface (bundled or third-party) may declare a views array of additional collections, each a full citizen (its own tabs, search, filters, detail modal, actions, bulk) with an optional capability gating just that view. Documented in docs/for-plugin-authors.md and validated on the System page's Integrations card.
  • Gravity SMTP debug log: the Email surface grows a Debug log view, the first consumer of the new slot: every debug line with priority tabs (Errors / Warnings / Info / Debug), search, and a detail view, gated on Gravity SMTP's own debug-log capability. The status card's "Debug log ↗" link-out to wp-admin is gone; the log lives in Minn now.
  • Gravity Forms form settings: each form's row on the Forms view opens Form settings: the whole estate (basics, layout, save-and-continue, restrictions, spam detection, options) drawn at request time from Gravity Forms' own Settings-framework schema, so a GF release that adds a field shows up in Minn without an adapter change. Saves go through GFAPI::update_form with GF's own semantics throughout: selects validate against their own choices, a duplicate form title is refused the way GF's screen refuses it, enabling Save and Continue runs GF's own activation (its resume confirmation appears), and the spam-confirmation toggle runs GF's own helper. Scheduling's date-time controls stay in GF, honestly counted as locked settings with a deep link.
  • Item-scoped settings views: the surface settings contract grows item scope: a route containing {id} renders per item instead of globally, entered from a row's settingsItem action (the Settings tab leaves the view switcher, and the toolbar names the item). Documented in docs/for-plugin-authors.md, validated on the Integrations card, and the Gravity Forms per-form settings above is the reference.
  • Gravity Forms notifications: the Forms surface grows a Notifications view listing every notification across forms (or per form via the tabs) with type-aware recipients: an email notification shows its address, a field-routed one resolves the field's label, a conditional one reads "Routing (2 rules)". Notifications activate and deactivate through Gravity Forms' own toggle (its hooks fire), and the daily fields (name, send-to, subject, message) edit in place through its own notifications store, with honest refusals: a bad address or duplicate name is named plainly, and a send-to typed on a routing notification explains that routing lives in Gravity Forms. Building notifications (events, conditional logic, routing rules) stays in GF's editor, one deep link away. The whole view is gated on GF's edit-forms capability through GF's own resolver.
  • Forminator support: its entries join the Forms surface as contact cards: answers summarized in form order, per-form tabs, search across every answer, and a detail card with labeled answers read from Forminator's own form models at runtime (so editing a form updates old entries' cards too). Delete routes through Forminator's own cleanup and is named honestly: Forminator has no entry trash, so the confirm says permanent. A Forms view lists each form with a live entry count and a one-click jump into Forminator's builder, and the whole surface honors Forminator's own permissions model, so a site that grants submissions to editors grants Minn's view the same way.
  • Formidable support: its entries join the Forms surface the same way: answer summaries in form order, per-form tabs, search across every answer, labeled detail cards read from Formidable's own field models at runtime, and permanent delete through Formidable's own destroy flow (its hooks fire; it has no entry trash and the confirm says so). Its permission model is honored: the granular entry capabilities its role settings can grant, with the administrator fallback its own screens use.
  • Everest Forms support: its entries join the Forms surface with the full Received / Spam / Trash workflow (status filter + when-gated actions): answer summaries in form order, per-form tabs, search across every answer, labeled detail cards read from the form's field map at runtime, trash and spam through Everest's own status helper (prior status preserved for restore), and permanent delete through its entry cleanup (hooks fire). A Forms view lists each form with a live entry count and a one-click jump into Everest's builder. Its view/delete entries capabilities are honored (with the manage-forms master cap).
  • Gravity SMTP Email Routing (2.3.0+): the Email surface grows a Routing view of conditional send rules (name, provider, enabled, condition summary), with enable/disable and delete through their own routing_settings store under their gravitysmtp_*_routing caps. Building and testing condition trees stays on Gravity SMTP's React screen (one deep link away). The status card reports rule counts and the Log gains a Filtered tab for the 2.3.0 partially-sent status (suppressed recipients stripped from to/cc/bcc).
  • WPvivid support: its backups join the Backups family: every completed set with components, size (from its own file list), local/remote pill and type, a status card with last backup, set count, schedule on/off and idle/running, Back up everything / Database only through its own prepare_backup + background run (the REST request returns immediately), and delete through its own delete_backup_by_id so local and remote cleanup stay its code. Locked sets refuse delete the same way WPvivid's screen does. Restores stay in wp-admin. When UpdraftPlus is not the active reporter, WPvivid also feeds the System Backups health check and the ⌘K "Back up site now" command.
  • BackWPup support: its jobs join the Backups family as local folder archives with run-now and delete through their own destination helpers (no freshness claims for remote destinations Minn does not list).
  • All-in-One WP Migration support: local .wpress exports list and delete through their Backups model. Export and import stay deep links to their screens; Minn does not claim backup freshness.
  • Simple Custom CSS and JS + Header Footer Code Manager: both join the Snippets surface (provider switcher when more than one is active). CCJ is a CPT shim with list/create/edit/activate/delete/bulk and a rebuild of their frontend search tree on write. HFCM reads and writes hfcm_scripts for the daily all-pages cases; page/post targeting pickers stay on HFCM's screen.
  • Surface list row actions: any surface list can open a ⋯ / right-click menu built from that collection's actions (the same shared pattern content, media and comments already use), so activate, delete and deep links stay one gesture away without opening the detail first.
  • Cache purge pack: Clear site cache detects SpeedyCache, Redis Object Cache, Breeze, Nginx Helper and Cloudflare alongside the existing providers, each still purged in its own isolated request.

Fixed

  • Gravity SMTP updates after license activate: Gravity SMTP freezes its license key on a request-scoped Common object and caches offerings for a day (their own plugins.php screen flushes that cache). Minn's post-activate force-check ran in the same request as the key write, still saw an empty key, and never offered 2.3.1. The force-check now refreshes their Common key from the store, drops their GFCache offerings entry, and the client re-fetches the updates map on a clean request after activate/verify.
  • License Deactivate / Re-verify from the ⋯ menu actually run: the per-row menu built its entries with fn while every other Minn context menu (and openMinnMenu itself) uses run, so clicking Deactivate or Re-verify closed the menu and did nothing. The license menu now uses run, and the menu helper also accepts a legacy fn alias so a misnamed entry never silently no-ops again.
  • Per-plugin Update clicks no longer crash each other: clicking Update on two plugins in a row used to fire concurrent Plugin_Upgrader runs. Those race on the filesystem, recycle the PHP worker, and the follow-up plugin list fetch dies with "Failed to fetch", blanking Extensions. Updates now queue one at a time (a second click toasts "Queued …"), the list reloads only after the queue drains, and that reload retries through the post-upgrade worker recycle instead of painting the empty error card. Server-side, a single-plugin update also skips a redundant wp_update_plugins() when the file is already known pending.

Improved

  • License activate force-checks for updates: after a successful license activate or re-verify, Minn forces a fresh plugins (and themes) update check so commercial plugins that only report updates once a key is stored (Gravity SMTP, Elementor Pro, and friends) light up immediately. If an update is available for that component, the toast names the version with a View updates action; either way the notifications panel and Extensions badges refresh from the same check. Extensions also gains an explicit Check for updates button (and a ⌘K command) that does the same force path without a license change.
  • Adapter expansion round (existing wiring, newer primitives): UpdraftPlus gains a real surface status card (last backup, set count, idle/running) with Back up everything / Database only actions through its own cron; Snippets family gets bulk activate/deactivate/delete (Code Snippets, WPCode, FluentSnippets) plus Active/Inactive filters on the two shimmed providers; Ninja Forms, Flamingo and Fluent Forms grow Received / Spam / Trash status filters with restore and permanent-delete where their models support them (bulk too); Everest Forms bulk mirrors its per-item spam/trash/restore; FluentSMTP gains a status card (14-day sent/failed chart, connection count) and a parameterized Send a test email action through its own test helper.
  • Adapter expansion round, continued: Elementor Pro form submissions get Received / Unread / Read / Trash filters with restore, permanent delete and bulk through their own Query helpers (opening a detail marks read); CFDB7 gets All / Unread / Read filters, mark-unread and bulk delete; Post SMTP gains resend plus a status card with a 14-day chart; Redirection gets a Settings view (permalink monitor, log retention, IP logging) written through red_set_options, plus bulk enable/disable/delete; Safe Redirect Manager, Simple 301 and EPS 301 all grow bulk delete.
  • Adapter expansion round, third pass: Forminator gains Received/Spam filter, mark spam/not spam and bulk delete; Formidable bulk delete; Wordfence surface status card (24h login counts + firewall/scan posture); Stream connector tabs; Aryo action tabs; WSAL and Simple History severity/level tabs expanded; WP Mail Logging status card (14-day chart) and bulk delete.
  • Editor accessibility first cut: the formatting toolbar is a labelled toolbar with named tools, the body is a multiline textbox, slash items are listbox options, config chips and block popovers (table, image, code, link, inspector) expose dialog roles with Escape dismiss and initial focus, and toasts/lock banners use live regions so assistive tech hears them. Suite: tests/editor-a11y.test.js.
  • Mobile Safari editor pass: fixed bottom chrome (word-count pill, toasts) tracks the software keyboard via visualViewport (--minn-kb-inset), notched phones get safe-area padding (viewport-fit=cover), toolbar tools and config chips grow finger-sized hit targets on phones, and the find bar uses 16px inputs so iOS doesn't zoom on focus. Desk writing is unchanged.
  • Editor Visibility is a themed combobox: the Publish card's Public / Password protected / Private control is Minn's searchable autocomplete now (same control as Parent and Template), not a native OS select popup.
  • Surface toolbars, calmed: a surface with a view switcher (Entries / Forms / Notifications) now stacks it on its own row with the current view's controls underneath, the same two-row shape Extensions settled on, instead of cramming the switcher, form tabs, status filters and search into one clipped line. On the second row, only one boxed strip remains: the status filter (Received / Spam / Trash) wears the quiet text style, and a long tab list (a site with more than a handful of forms) becomes the themed searchable dropdown instead of a pill strip that scrolls past the edge. Short tab lists keep their pills, and simple surfaces keep the single row.
  • Content header and filters, calmed: the Content toolbar follows the same two-row pattern (type filter on its own row; categories, tags and search underneath) so a long CPT list no longer clips filters off the edge. More than six post types become a searchable combobox.
  • Theme follows the OS, with an explicit menu: until you choose, Minn matches the system light or dark preference and flips live when it changes. The theme control also right-clicks (or long-presses) into Dark / Light / System, and System is the default for a fresh browser. An explicit choice still wins forever.

Fixed

  • Inline code from backticks is undoable again: wrapping with ` code used a direct-DOM insert (Blink rewrites bare <code> from insertHTML into a styled span), so ⌘Z could not restore the backticks. The wrap now rides insertHTML` with a one-shot zero-width spacer so a real code chip lands on the undo stack; the toolbar code toggle uses the same path.
  • IME composition no longer breaks the editor: markdown wraps, code-edge escape, island Backspace arming, slash-menu Enter and figcaption Enter all used to fire on every keydown, including intermediate IME steps (CJK candidates, dead keys). They now bail while isComposing (or legacy keyCode 229) so candidates aren't stolen mid-composition. Latin markdown is unchanged. Suite: tests/ime.test.js.
  • Revision diff white corner in dark mode: the side-by-side revision modal painted a bright white square where the scrollbar tracks meet (WebKit's default scrollbar-corner + light color-scheme). The corner is transparent/theme-matched now and the diff scroller declares a dark color-scheme in dark theme.
  • Media multi-select no longer covers the type badge: the grid checkbox and the IMG/VID/… label both lived in the top-left corner, so hover/select stacked the check on the badge. They now sit in opposite corners (badge left, checkbox right).
  • Update everything reloads after Minn updates itself: the notifications panel's Update everything path already bulk-updated plugins (including Minn Admin) but only soft-refreshed the SPA afterward, so a self-update left the old app.js, CSS and version badge in memory. It now hard-reloads the same way the Extensions single-plugin and bulk Update buttons already did.
  • Detail-modal link actions now fill every {field} placeholder: an adapter action's href documented {field} substitution from the item, but the modal renderer only filled {id}, so multi-key deep links (a form id plus a notification id) rendered with literal braces. Both now use the same substitution.

v0.12.0 - July 12, 2026

The workflow release. Surfaces grow from lists into complete workflows: schema-driven settings views, bulk actions with shift-select, status filters, parameterized actions, setup gates for first-run installs, and honest outcome reporting, all proven end to end on Gravity Forms and Gravity SMTP. Six more plugins join the families (Perfmatters, Ninja Forms, Solid Security, Limit Login Attempts Reloaded, WP Mail Logging, Duplicator), Settings mirrors WP 7.0's new Connectors registry, the license manager settles in beside the plugins it describes on Extensions → Licenses, and the header wears the site's own name and icon so you can tell which site you're in at a glance.

Added

  • Solid Security support: its lockouts join the Activity Log family: every host, user and username lockout with a locked / expired / released pill, a "Locked out now" tab, search, and a status card reporting who's locked out right now, all-time lockouts, banned hosts and which protection modules are on. Actively locked rows carry a Release lockout action through Solid Security's own lockout API, and the System page gains a Solid Security posture row (brute force protection on or off, with firewall and two-factor noted). Its dynamically granted management capability is honored, so sites using its user-groups feature keep their access model.
  • Ninja Forms support: entries join the Forms surface as contact cards: answers summarized in form order, per-form tabs, search across every field, and a detail card with labeled answers, entry number and submission time. Field labels are read from Ninja Forms' own models at runtime, so editing a form updates old entries' cards too, and answers whose field was since removed still show. A Forms view lists each form with a live entry count and a one-click jump into Ninja Forms' builder, and Trash routes through its own submission model (restore stays on its screen; the confirm says so). Its submissions capability filter is honored, so a site that grants entries to editors grants Minn's view the same way.
  • Duplicator support: its packages join the Backups family: every package with its archive size read from the files on disk, who built it, and a completed / building / error pill; a status card with the newest package, package count and total disk footprint (honestly labeled: free-tier packages are manual builds, so Minn makes no freshness claims, the Disembark rule); and package delete routed through Duplicator's own cleanup so archive files, logs and temp files go with the row. Building a package stays on Duplicator's screen, one click away.
  • WP Mail Logging support: its email log joins the Email family: every logged send with sent/failed status, tabs, search, a detail view with the full message (HTML mail renders sandboxed) plus headers, host and the error text, Resend routed through the plugin's own resender service (so recipient splitting, header cleaning and attachment paths stay its logic, and the new attempt appears as its own log entry), and permanent delete matching its log screen. Its "who can see submission data" capability setting is honored.
  • Limit Login Attempts Reloaded support: the lockout log joins the Activity Log family. Every lockout with the username, IP, attempt count, gateway (login form, XML-RPC, password reset) and a lifecycle pill (locked / expired / unlocked), a "Locked out now" tab, search, and a status card showing who's locked out right now, failed attempts in the last 24 hours, all-time lockouts and the configured policy. Actively locked rows carry an Unlock IP action that mirrors the plugin's own unlock handler through its own Config store. Plugin settings stay on its screen, one click away.
  • Perfmatters support, and settings-only surfaces: a surface can now declare settings with no collection at all and its settings view renders as the whole page, the right shape for plugins that are configuration rather than data. The bundled Perfmatters adapter is the first: a Performance page under Tools with all nine of its settings tabs (General, JavaScript, CSS, Code, Preload, Lazy Loading, Fonts, CDN, Analytics) drawn at runtime from the plugin's own core-Settings-API registrations, so a Perfmatters update that adds a field shows up in Minn without an adapter change. Saves merge only the edited keys and go through Perfmatters' own registered sanitizer (one-per-line lists normalize exactly like its own form), unknown keys never write, and the handful of fields drawn by bespoke callbacks count as locked with a link to the full screen.
  • Gravity SMTP suppressions: the Email surface's view switcher gains Suppressions: the addresses Gravity SMTP refuses to send to, listed with reason and notes, searchable, with suppress-an-address (create form) and reactivate, all through Gravity SMTP's own model under its granular suppression capabilities. Reads use a direct scoped query because the plugin's own count and search disagree on partial terms, which would have made the pager lie. The status card links out to the debug log until surfaces grow a third list view.
  • Status filters on surfaces: a collection can declare a filter (a second dimension beside the tabs, rendered as a segmented control) whose value rides a plain query parameter or merges into the same JSON criteria object the search box uses, for APIs like Gravity Forms that take both in one param. Gravity Forms entries get Received / Spam / Trash views out of it, which finally makes the whole workflow round-trip inside Minn: spam and trashed entries are visible, Not spam, Restore and Delete permanently appear exactly where they apply, and the bulk bar only offers verbs at least one listed entry can take.
  • Actions can report honest outcomes: an action route may return a message that replaces the default "done" toast. Gravity SMTP's send-a-test and resend use it for the multi-mailer reality: only one mail plugin can own the sending pipeline, so when another active mailer (FluentSMTP, say) carries the send, the email delivers but never appears in Gravity SMTP's log. The toast now says exactly that instead of implying it was logged.
  • Parameterized actions: a surface action (detail modal or status card) can declare fields, and clicking it swaps the button row for an inline form whose values ride the request. First consumers: Send a test email on the Email surface's status card (through Gravity SMTP's own force-connector pattern) and Add note on Gravity Forms entries (shimmed through GFAPI::add_note; Gravity Forms' own REST notes route creates the note but then fatals building its response). The status card also now reports the active sending service and test mode at a glance.
  • Bulk actions on surfaces: any surface (bundled or third-party) can declare bulk actions and its list grows a checkbox column with shift-range select, a Select-page control and a selection bar. Actions apply per item so one failure never aborts the rest, per-item conditions skip ineligible rows in a mixed selection, and the result toast counts done, skipped and failed. Documented in docs/for-plugin-authors.md, validated on the Integrations card.
  • Gravity Forms entry workflow: entries can be starred and unstarred (singly or in bulk), marked as spam, trashed in bulk, and their notifications resent, all through Gravity Forms' own workflow endpoint under its own capabilities. Opening an entry marks it read exactly like GF's own screen, and entry notes now render as a section on the entry card (which used to drop sections it didn't recognize). Restoring from spam or trash stays in wp-admin until Minn grows a status filter, and the actions say so honestly.
  • Gravity SMTP, fully at home: the Email Log surface grows a Settings view built from Gravity SMTP's own settings schema. The Sending tab lists all 21 connectors, renders the primary connector's configuration (host, credentials, from controls, whatever that connector declares), and switching the primary service reloads the tab with the new service's own fields; the General tab covers test mode and the email and debug log controls. Everything reads and writes through Gravity SMTP's own data stores, so GRAVITYSMTP_* wp-config constants keep winning and stored secrets stay behind their **************** mask (an unchanged mask never overwrites the real value). The surface now honors Gravity SMTP's granular gravitysmtp_* capabilities instead of a flat admin check, the email detail is enriched through its own models (from, cc, bcc, source, resend eligibility), and Resend replays the original recipients, headers and attachments through the configured connector rather than approximating with a plain send. One-click OAuth handshakes (Google, Microsoft, Zoho) stay on Gravity SMTP's own screen, honestly counted as advanced settings with a link.
  • Settings views for surfaces: an adapter (bundled or third-party) can now declare a settings key on its surface and get a real settings UI in Minn: tabs it names, forms drawn from a schema its own route serves at runtime, saves routed back through the plugin's own settings APIs. Only edited keys ride a save (untouched values never round-trip through a plugin's sanitizers), masked secrets that ride back unchanged never clobber the stored value, a refused save keeps the form as typed, and a group's locked count links the too-bespoke remainder to wp-admin. Because the schema is read from the live plugin, a plugin adding a field updates its own coverage with no Minn release. The contract is documented in docs/for-plugin-authors.md and validated on the System page's Integrations card.
  • WP 7.0 Connectors: Settings gains a Connectors section mirroring core's new connector registry (AI providers and other external services). Each connector card shows its connection state and where its key comes from: a saved key, a wp-config constant or an environment variable, with the latter two honestly read-only since they win over anything saved. Cards install or activate the provider's companion plugin in place, link to the vendor's key page, and save keys through core's own settings route, so core masks every response (a raw key is never echoed back to the browser) and validates AI provider keys against the live provider. A rejected key is named plainly, kept in the field for a retype, and never stored. Third-party connectors registered through core's wp_connectors_init appear automatically.
  • Setup gates: a freshly installed plugin often needs its own first-run install (tables, default groups) before its surface can work, and pointing a fully-armed surface at it produced raw errors deep in a form. A surface can now declare a setup gate: until the plugin's own readiness check passes, the surface renders a setup card in place of the list, with the plugin's wizard questions as toggles and one Set up now button that runs the plugin's own installer. The bundled Redirection adapter is the reference (monitoring and logging surface as toggles; IP logging defaults off, a privacy choice Minn won't make silently), setups Minn genuinely cannot run inline render an honest link-out, and the contract is documented in docs/for-plugin-authors.md and validated on the Integrations card.

Fixed

  • Table, image and code chips wiggled during scrolling: the ⚙ chips on editable tables, images and code blocks were pinned to the viewport and chased the page per scroll frame, so fast scrolling made them jitter, drift past their block and snap back (worst with the trackpad's elastic bounce). They now live inside the scroller at content coordinates like island chips, riding the scroll natively with zero lag, and re-anchor whenever the page actually reflows (late image loads, block previews rendering) instead of on every scroll tick. The sticky toolbar covers passing chips naturally.
  • Combobox panel detached during fast scrolling: a dropdown panel that had re-anchored to the viewport (the no-room-below escape) chased the page during scrolling and visibly lagged behind it, showing a gap between the panel and the content until the scroll settled, worst with the trackpad's elastic bounce. A re-anchored panel now closes on a real page scroll, exactly like a native select; panels that fit in place still ride the scroll seamlessly, scrolling inside the option list never closes it, and the highlighted option is revealed by scrolling only the list itself (revealing it the old way could nudge the page and instantly re-close the panel).
  • ACF panel saves failed with an empty select in the group: ACF reports false over REST for any field without a value, including selects and text fields. Panel saves round-trip the whole values object, so that sentinel made ACF's own validation reject the write and every panel save on the post failed with a 400, while the editor looked fine. Empty values now normalize on load, and clearing a select sends the null ACF expects.

Improved

  • "Week starts on" is a themed dropdown: Settings → Site now renders it as Minn's searchable combobox like the other pickers, instead of a native OS select popup.
  • The header wears the site's own identity: the sidebar logo used to say the product twice (the "m" mark and a "minn" wordmark). Now the mark is the site's WordPress Site Icon when one is set (falling back to the gradient "m" tile), and the wordmark is the site name, so you can tell which site you're in at a glance, the same context wp-admin gives. The name falls back to "minn" when a site has no name, and a long title truncates rather than pushing the version badge around. Changing the Site title or Site icon in Settings updates the header immediately, no reload.
  • A quiet way back to wp-admin: the account card now carries a WordPress mark beside Log out that opens the classic admin in a new tab. The exit used to live only in the ⌘K palette and the contextual "Edit in wp-admin ↗" links, so someone who didn't know the palette had no visible way out. It stays deliberately quiet (a small icon, not a prominent topbar button): Minn is where you work, wp-admin is a tool you dip into.
  • One Time Login gets its first UI: that plugin is CLI-only (it ships no admin screen), so the users row menu now offers Copy one-time login link, minting a single-use login-as-that-user link through the plugin's own token generator and copying it to the clipboard. The link is a secret, so it's generated on demand and never stored; the endpoint is gated on edit_user for the target, matching the plugin's own REST route. When "Minn is the default admin" is on, a one-time login lands in Minn too (the plugin hardcodes a wp-admin redirect that skips the normal login filter, so Minn intercepts its own post-auth hook).
  • Switched sessions get a way home: switching to another account via User Switching used to be a one-way door in Minn (the plugin's switch-back link lives in wp-admin's admin bar, which Minn never renders). A switched session now shows an amber Switch back to ⟨you⟩ bar above the user card, through the plugin's own nonce URL, landing back in Minn as yourself.
  • Health cards with a destination are clickable: System health cards that have somewhere to act now carry a small ↗ and go there: Backups opens the Backups surface, Debug mode scrolls to the Debug tools card, a pending WordPress update opens Extensions, a hidden site opens Settings → Visibility, and Licenses opens the license manager. Adapter posture rows can declare an href (Wordfence's firewall and scan rows open its own screens; Solid Security's row opens its dashboard). Cards that are pure facts with no in-app fix (PHP version, HTTPS, memory) stay plain on purpose.
  • The license manager moves to Extensions → Licenses, de-noised: licenses now live beside the plugins and themes they belong to, as a third Extensions tab. Rows group by state (needs attention first, then valid, then no license), inactive components collapse behind a count, and only Activate stays an inline button: deactivate, re-verify and turn-on tuck into a per-row ⋯ menu built from what that row can actually do. The System page keeps the Licenses health check (now clickable, jumping straight to the manager) and the copy report's licenses section; the big card and its ~40 always-visible buttons are gone.
  • Extensions toolbar, calmed: the view switcher (Plugins / Themes / Licenses) sits on its own row with page-wide Update all beside it, and the second row is consistent across tabs: quiet text filters with counts (no more boxed pill strip stacked on a boxed tab strip), then search and the Add button aligned right.
  • Plugin icons load themselves: wp.org icons and directory links ride the update-check transient, which every plugin activate/deactivate wipes. When it's empty, Minn now primes it on demand instead of showing letter tiles until the next cron check, so a site whose only admin is Minn still gets real icons.
  • Adapter dropdowns are themed autocompletes: every select an adapter declares (surface settings, create and edit forms, parameterized action fields) now renders as Minn's strict searchable combobox instead of a native OS select popup, the same control the Email surface's primary-service picker already used. Typing filters, the current choice stays highlighted, and an untouched control still submits exactly what an untouched select would. Editor sidebar panels and the block inspector deliberately keep native selects (compact, and their clear-to-default semantics live there).
  • Images can link, and the lightbox is a toggle: the image popover gains a Link URL field (with open-in-new-tab) and an "Expand on click" lightbox switch, closing two gaps where the block editor was still required. The link is stored exactly as Gutenberg stores it (the anchor wrapped inside the figure), so posts stay valid in both editors, and the two options are mutually exclusive with an explanation, matching core's own rule.
  • Focus and outline mode wear an exit chip: entering either mode used to leave no visible way out (the entry toast names the shortcut, then vanishes). The topbar now shows a dismissible "Focus mode ✕" / "Outline mode ✕" chip beside the editor's status badge; clicking it exits, and it survives reloads with the persisted mode. A back arrow was considered and rejected: it reads as "leave the editor," and this is a view mode, not a place.
  • Recent activity is clickable: the Overview feed's rows navigate to where the activity happened: posts and pages open in the editor, comments land on the matching moderation tab.
  • Gravity Forms notification notes read clean: notes written by notification logging store raw HTML that wp-admin renders; Minn's entry card showed the markup as text soup. Notes now render as plain text with the note's link (View Email and friends) surfaced as a proper link row.
  • The mail surface is called Email now (it grew settings and a status card; "Email Log" undersold it and read oddly as a place to configure sending). Gravity SMTP's view switcher reads Log / Settings, and the primary-service picker is the same themed autocomplete used everywhere else in Minn instead of a 21-option native select. The form engine gained combobox as a first-class field type for any adapter's settings.
  • One form engine: the three field renderers that grew up independently (surface create and edit forms, editor sidebar panels, the block inspector's generated controls) now render through a single engine with one field vocabulary, one value reader and one coercion path. Nothing changes for adapter authors except more consistency: edit fields accept the full create vocabulary (textarea, select, tags, rows, placeholder), and the Integrations card now validates create and detail.edit field lists (unknown types, selects without options, unknown keys) instead of letting them fail silently in the app.

v0.11.0 - July 11, 2026

The licenses release. The System page grows a full license manager: every paid plugin and theme classified from the vendor's own locally stored state, with paste-to-activate, deactivate and re-verify wired through each vendor's own code and proven against the live licensing services of more than twenty vendors. Around it, the daily-work gaps close (a terms manager, bulk actions for media, comments and users, media captions, post formats, Custom CSS), Settings reorganizes around intent instead of history, and the site's posture becomes glanceable: Minn now warns when the site is hidden from the public and reports firewall, SSL, loopback and REST health at the same glance.

Added

  • License visibility: the System page gains a Licenses card listing every paid plugin and theme with a state pill (valid, expired, invalid, missing or unknown), the vendor's expiry where one is stored, and a health check that flags expired or invalid licenses. Everything reads from locally stored vendor state: no network calls, no vendor code execution, so looking can never burn an activation seat. Bundled readers cover Elementor Pro, ACF PRO, WP Rocket, Gravity Forms, Bricks, Divi, Beaver Builder, WPBakery, Brizy, Etch, AnalyticsWP, Avada, Slider Revolution, LayerSlider, Rank Math Pro, Envato Market and the Brainstorm Force family, plus generic Freemius, EDD Software Licensing, SureCart and StellarWP/PUE detection via SDK fingerprints. Third parties join through the minn_admin_license_providers filter, the card rolls into the copy report, and rows for inactive components still read their stored license truthfully.
  • License activation: license rows grow paste-to-activate, deactivate (behind a confirm) and re-verify controls that route through each vendor's own activation code. Guardrails throughout: a pasted key rides one request and is never stored, logged or echoed back; a failed activation is never retried automatically (retries can burn paid seats) and keeps the field in place with the typed key selected for a quick retype; hitting a site limit is named plainly instead of reading as a generic error; controls render only while the vendor's code is loaded; a rejected key never leaves residue (prior key and status are snapshot-restored). Wired vendors, each proven against the live service: Elementor Pro, ACF PRO, WP Rocket, Beaver Builder, Brizy Pro, Etch, Bricks, Divi (username plus API key), Gravity Forms, Gravity SMTP, The Events Calendar family (Events Calendar Pro, Event Tickets Plus, Filter Bar, Community), Kadence Blocks Pro, WPMU DEV, SearchWP, Gravity Perks, GP Premium, Perfmatters, WP All Import Pro, WP All Export Pro, Slider Revolution and LayerSlider. Portal-handshake vendors (WPBakery, Rank Math Pro, Envato Market) get an Activate ↗ link to their own screen instead of a paste field that could not work. Vendors that keep no readable local state (Gravity SMTP, Brizy) show Minn's own last check result with honest wording ("verified 2 hours ago from Minn"). The contract, including multi-secret fields and the tested-vendor table, is documented in docs/license-manager.md and docs/for-plugin-authors.md.
  • Turn a licensed component back on in place: dimmed rows for inactive plugins and themes carry a small power button (shown only when the file exists and you hold the capability) that activates the component and re-renders the card, revealing its license controls. Themes confirm first, since that switches the site's active theme.
  • Terms manager: Manage → Structure covers every REST-enabled taxonomy that organizes public content, with a switcher (categories and tags first), an indented tree for hierarchical taxonomies, inline create and edit (name, slug, parent, description), delete with confirms that say what actually happens, and count links straight into the filtered content list. Merge is the one new primitive: pick a surviving term and every post moves over through core's own reassignment machinery before the source is deleted. Editors get it through their normal manage_categories capability.
  • Bulk comment moderation: comment rows carry checkboxes with shift-range select and a Select-page control; the selection bar offers the current tab's own verbs (Approve, Spam, Trash, Restore, Delete forever), so a batch can never apply a status the tab doesn't offer.
  • Bulk media select and delete: grid tiles and list rows gain checkboxes (hover-revealed on the grid) with shift-click range select and a selection bar. Bulk delete confirms once, then deletes per item so one failure never aborts the rest.
  • Media captions and descriptions: the media detail modal now edits Caption and Description alongside title and alt text, fetched lazily so the library list stays light.
  • Bulk role change: the users table gains a checkbox column and a bar to change every selected user's role in one action, using the same themed combobox as the rest of the app. Your own account is skipped by the batch, with a note, so you cannot demote yourself mid-batch.
  • Per-post format picker: the editor's Settings card offers the post format (aside, gallery, link and the rest) when the active theme declares post-format support, hidden exactly as wp-admin hides it otherwise.
  • Custom CSS: Settings gains a Design section editing core's per-theme Additional CSS (the same store the Customizer uses), gated on the edit_css capability. Structural validation refuses unbalanced braces or unclosed comments without writing, and a refused save keeps the typed CSS in the editor instead of re-rendering over it.
  • Site visibility warnings: a site can be silently invisible to the public (a maintenance or coming-soon plugin, a whole-site password gate, or "discourage search engines" left on after launch) and its owner never notices. Minn now detects all of it read-only from local options and says so: an amber Overview banner, a persistent topbar chip on every route, and a System health check that appears only when something is hiding the site. The chip opens a popover with the actual control where Minn can safely flip it (its own maintenance mode, search-engine visibility); third-party gates link out. Bundled detectors: WP Maintenance Mode, SeedProd, Under Construction, Password Protected, WooCommerce coming soon, Elementor maintenance mode, Minn's own maintenance mode and the search-visibility setting; WooCommerce's store-pages-only shape reads as "Partly hidden" rather than claiming the whole site is dark. Third parties register through the minn_admin_visibility_providers filter.
  • Security posture on System: with Wordfence active, health rows report the firewall mode (blocking, learning or off) and the last scan with its unresolved issue count. With Really Simple SSL active, an SSL-enforcement row reports whether the whole site redirects to HTTPS, which the generic HTTPS check cannot prove. The WordPress group also shows the real login URL, honoring login-hider plugins.
  • Loopback and REST self-checks: two health rows driven by core's own Site Health tests catch the failure that silently kills cron, scheduled posts and background updates, cached for 15 minutes.
  • Autoload and Cron detail modals: the System page's autoload breakdown and cron row (cards and grid rows both) expand into wide modals: every autoloaded option by size, and every scheduled event with its next run, recurrence and overdue highlighting.
  • Tools card: deep links to wp-admin's one-shot jobs (Site Health, export and import content, the GDPR personal-data tools), the honest link-out instead of a rebuild.
  • Order PDFs: with PDF Invoices & Packing Slips active, the order modal offers a download link per enabled document through the plugin's own endpoint and nonce.
  • Switch to this user: with User Switching active, the users row menu gains a switch action riding the plugin's own nonce URL.
  • Regenerate thumbnails: with Regenerate Thumbnails active, the media detail modal gains a ↻ Thumbnails action running the plugin's own regenerator server-side.
  • SiteSEO in the SEO panel, WP Armour on the Spam page (all-time blocked count from its honeypot, deliberately no toggles) and 301 Redirects (WebFactory) in the Redirects family (list, search, create, edit and delete, with its 404 log kept out of the rule list).
  • Theme follows the OS: until you explicitly toggle, Minn now matches the system's light or dark preference and flips live when it changes. An explicit choice still wins forever.

Improved

  • Settings reorganized by intent: the historical General/Writing/Reading/Discussion tabs are regrouped by the job you're doing: Site (identity, locale, admin), Visibility (search engines, maintenance mode, membership), Homepage, Content (new-content defaults plus permalinks), Comments (discussion plus spam, because they are the same job) and Design. The section nav is sticky, and a tab that shows settings from more than one save endpoint persists them all in one click.
  • Structure page: Post Types, Taxonomies and Terms are three tabs on one Manage page instead of separate nav items, gated individually (an admin sees all three, an editor sees Terms). The taxonomy tab's term counts cross-link into the Terms tab in place.
  • System page order and jump bar: Licenses moves up under the health checks (licensing is daily work; PHP info is reference), and a sticky jump bar (Health, Licenses, Debug, System, Extensions, Integrations) smooth-scrolls between sections with a scroll-spy pill.
  • Revision browsing: the revision diff modal steps with the left/right arrow keys and header buttons with a position count, so flipping through versions no longer means close, click, reopen.
  • Visibility controls update live: toggling maintenance mode or search-engine visibility from Settings, the chip popover or the Overview banner refreshes the banner, chip, Settings page and System health check in the same session, no reload.

Fixed

  • Theme cards wore two update badges: an updatable theme showed the overlay badge on its screenshot and the Update button below it. The badge now renders only for users who can't run updates; everyone else gets just the button.
  • Session list showed dead sessions: the profile modal listed expired session tokens core itself filters out, padding the list with rows offering a pointless sign-out, and same-day logins were indistinguishable. Expired tokens are now dropped and each row shows a precise sign-in time.
  • Modal comboboxes clipped their options: a dropdown panel inside a modal was cut off at the modal edge (the Add-user role picker lost its lower roles). Panels that would spill now re-anchor to the viewport and flip above when there's no room below; everything that fits is untouched.
  • "email · email" user labels: users whose display name is their email (common for imported accounts) showed the value twice in delete, send-email and reassign controls.
  • Content shifted sideways between pages: navigating between a tall page and a short one changed the scrollbar's presence and re-centered the content a few pixels left or right. The scrollbar gutter is now reserved app-wide.
  • Install-modal drops landed in Media: with Add plugin or Add theme open, a zip dropped a few pixels outside the dropzone uploaded to the media library. Any drop while the installer is open now routes to the installer.
  • Integrations card falsely flagged status: the descriptor validator rejected the documented surface status key, so a correct adapter (Disembark) read as misdeclared.
  • Order modal Status block padding: the status controls sat flush against the modal edge.

v0.10.0 - July 10, 2026

The surfaces release. One nav item per job, with every capable plugin layered in behind it: Forms (now including Contact Form 7 via Flamingo or CFDB7), Email Log, Activity Log, Snippets, Redirects and Backups (UpdraftPlus and Disembark) are first-class Minn views with a provider switcher, and the sidebar reorganizes into Workspace, Tools and Manage. Around them: admin notices extracted into a safe digest (with background actions and Hide), one-click Update everything, Clear site cache across a dozen providers, find & replace in the editor, a Spam settings page, Site Kit traffic, and Integrations diagnostics so a misdeclared surface explains itself.

Added

  • Spam settings page: Settings gains a Spam section showing who filters comment spam and what happens to it. Active providers (Akismet, Antispam Bee, CleanTalk bundled; others via the minn_admin_spam_providers filter) each get a card with configured state, all-time blocked count, a few safe toggles and a link to their full screen. The page also carries the spam-queue count with a jump to the Comments spam tab (or a plain explanation when commenting is disabled) and core's Disallowed Comment Keys blocklist, editable in place.
  • Integrations diagnostics: the System page gains an Integrations card: a live registry of every surface, editor panel, design source, cache purger, page builder and hook listener, each attributed to the plugin that registered it, with descriptor problems flagged (unknown keys, missing routes, columns without keys). A malformed integration used to fail silently in the app; now it explains itself, and the copy report carries the section for tickets.
  • Open design-library seam: any block plugin can now put its template library in Minn's slash menu and block picker by answering the new minn_admin_design_sources filter; the picker groups each library under its own name. The bundled Stackable, Kadence and GenerateBlocks adapters register through the same filter, and the two-endpoint route contract is documented in docs/for-plugin-authors.md.
  • Security activity log (Wordfence): Wordfence joins the Activity Log family with a login-security view: every sign-in and failed attempt, with usernames and decoded IPs, filterable by success/failure and searchable. Firewall and scans stay in wp-admin. New docs/plugin-support.md maps everything Minn covers.
  • Add theme opens with popular themes: the Add theme dialog now preloads the WordPress.org popular directory instead of a blank search box, so there's always something to pick.
  • Backups surface (UpdraftPlus): a read-only Backups view lists every backup set (components, size, where it's stored, when), a Backups health check on the System page answers "is my site backed up?" at a glance (pass under 36 hours, warn under 8 days, fail beyond or on errors), and ⌘K gains Back up site now, which starts a backup through UpdraftPlus's own background machinery and never runs it in-request. Restores stay in wp-admin.
  • AIOSEO and SEOPress in the SEO panel: the editor's SEO panel (title, meta description, focus keyword) now covers All in One SEO and SEOPress alongside Yoast and Rank Math. AIOSEO stores in its own table rather than postmeta, so Minn reads and writes through AIOSEO's own model; additional keyphrases are preserved and clearing a field removes it cleanly. The first active SEO plugin wins, in install-base order.
  • Site Kit traffic: sites running Google Analytics through Site Kit get the real Overview traffic chart with no dedicated analytics plugin. Reports flow through Site Kit's own REST module as the current user, so Google auth, dashboard sharing and API quotas stay Site Kit's job. A purpose-installed analytics plugin still answers first; Site Kit fills in when none is active, with results cached for 15 minutes.
  • Email Log family: FluentSMTP, WP Mail SMTP and Post SMTP join Gravity SMTP under one Email Log nav item with a provider switcher. FluentSMTP and Post SMTP show the full send log (subject, recipients, sent/failed, message body) and FluentSMTP supports one-click Resend; WP Mail SMTP (free) surfaces its debug events, which is where that plugin records delivery failures. All read-only database shims: serialized recipient blobs are mined with regexes, never unserialized, and each plugin's local-versus-UTC timestamp convention is normalized so relative times read true.
  • Clear site cache: one ⌘K command purges every cache layer the site runs. Bundled providers: Kinsta (page, CDN, object cache and OPcache via the hosting mu-plugin), LiteSpeed Cache, WP Super Cache, W3 Total Cache, WP Rocket, WP Fastest Cache, SiteGround Optimizer, Autoptimize, WP-Optimize, Cache Enabler, Hummingbird and Elementor's generated CSS. Each layer purges in its own isolated request, so one broken cache plugin never blocks the rest; third parties can add providers with the minn_admin_cache_purgers filter.
  • Duplicate: the content row menu can duplicate any post or page as a new draft. Content, excerpt, taxonomy terms and meta (builder data, featured image, SEO fields) ride along, and an Open action in the toast jumps straight into the copy.
  • Update everything: the notification panel's Updates tab pins a single button that runs every pending plugin, theme and WordPress core update in one click (core goes last, with poll-verified completion), shows each step while it works, then reports what changed.
  • Core updates, front and center: a pending WordPress update now shows a banner on the Overview page and an amber chip in the topbar on every screen (alongside the existing Extensions banner, notification item and a new System health check). Updating polls for completion, so a connection dropped while core files are replaced can no longer report a false failure; the poll also finishes a missed database migration. When WordPress updates itself (minor releases do), a notification says so instead of the update nag silently vanishing.
  • Theme updates surface: pending theme updates light the Extensions dot and appear in notifications; clicking one lands on the Themes tab.
  • Admin-notice digest: notices other plugins print in wp-admin now land in Minn's notification panel under a new Notices tab. Minn triggers a background dashboard pageload as the current user, renders each registered notice callback in an isolated buffer, and extracts structured data only (severity, plain text, action links, owning plugin via Reflection). No third-party HTML, CSS or JavaScript ever reaches Minn.
  • Notice actions run in the background: a notice's own links render as buttons on the row. Allow, dismiss and opt-in style links (the ones that reload the page they rendered on) run without leaving Minn, the plugin's own security nonce reaches its handler untouched, and the digest refreshes so an actioned notice disappears on the spot; external links open in a new tab.
  • Hide any notice: every row on the Notices tab gets a Hide button (with Undo) that clears the notice from Minn's digest. Some plugins wire their notice dismissal to their own admin-ajax JavaScript, which no extraction can replay; Hide covers those and anything else you are done seeing. A hidden notice stays hidden across re-captures until its text changes, and hiding is per-user in Minn only: wp-admin is untouched.
  • Find & replace in the editor: ⌘⇧F opens a find bar over the post (also in ⌘K); plain ⌘F stays the browser's native find. Matching works the way a writer expects: case-insensitive with an Aa toggle, matches cross bold, italic and code boundaries but never cross blocks, and protected block islands are left alone. Enter and ⇧Enter step through highlighted matches, Replace and Replace-all rewrite through the editor's native input path so ⌘Z steps back one change at a time, and Esc closes with the current match selected.
  • Disembark in the Backups family: sites using the Disembark connector get a Backups view that tells the truth about a pull-based tool: a status card with the last scan, database size and working files on disk, the exact disembark connect command as a click-to-copy box (also in ⌘K as Copy Disembark backup command, fetched on demand so the site token never rides a pageload), scan sessions with per-session delete, workspace cleanup, and token regeneration. Minn never claims backup freshness for Disembark; the site cannot know a pull completed.
  • Surface status cards: adapters (bundled or third-party) can now declare a status route on any surface and get a card above the list: server-built stat rows, an optional copy-to-clipboard command box, and action buttons with confirm and refresh semantics. The Disembark adapter is the reference; the shape is documented in docs/for-plugin-authors.md.
  • Contact Form 7 joins the Forms family: the biggest form plugin in the ecosystem, through both of its popular storage plugins. With Flamingo (CF7's own companion), messages render as contact cards with per-form tabs, spam and unspam run through Flamingo's own handlers (Akismet reporting rides along), trash stays restorable in Flamingo, and CF7 forms list in the Manage view with shortcodes and message counts. With CFDB7, entries are read from its serialized rows without ever running unserialize (a byte-length scanner walks the data instead, so hostile content cannot execute), opening a message marks it read like CFDB7's own screen, and delete is honest about being permanent. Form building stays in CF7's editor, one click away.
  • Snippets surface: Code Snippets, WPCode and FluentSnippets list, toggle, create and edit from Minn. One Snippets nav item with a topbar provider switcher when more than one is active.
  • Forms family: Fluent Forms and Elementor Pro join Gravity Forms under one Forms nav item. Entry details use a contact-style card (name, email, message body, quiet meta) instead of a raw field dump. ←/→ still steps entries on the page.
  • Redirects edit: Safe Redirect Manager and Simple 301 Redirects support in-place edit (not list-only). Redirect adapters collapse to one Redirects nav item with a provider switcher.
  • Activity Log family: WP Activity Log, Aryo, Stream and Simple History collapse to one Activity Log nav item. Event detail uses the same card language as form entries (who, event message, short context, meta chips) with open-in-log and Simple History action links where available.
  • Users context menu: right-click (or ⋯) a user for View, Copy email, Send password reset, Send email (styled HTML from the site), Sign out sessions, Edit in wp-admin, and Delete with a reassign autocomplete. REST: users/{id}/reset-password and users/{id}/email.
  • Buttons live island: slash Buttons inserts a multi-row CTA editor (label, URL, new tab, outline, add/remove). Nested core/button markup stays Gutenberg-valid; non-edited attrs (e.g. colors) are preserved.
  • Interactive Details island: expand/collapse, type the summary and body in the card (no free top-level <details> that traps the caret).
  • Shortcode island field: type [shortcode …] in the island; no browser prompt.
  • Pullquote as editable prose; slash insert for Spacer, File and Shortcode (Basics always lists them, including on classic-mode posts; insert promotes to blocks mode).
  • Add plugin categories: SEO, Forms, Ecommerce, Security, Backup, Analytics, Cache, Email/SMTP, Redirects, Dev tools, Spam, Blocks. Each chip runs a plain WordPress.org search so the directory ranks popular options.
  • Admin bar "Edit in Minn Admin": on a singular front-end view you can edit, the bar node retargets to that post/page in the Minn editor; elsewhere it stays Minn Admin → the app home.

Improved

  • Sidebar in three groups: the navigation now separates the act-on-it set (Workspace: Overview, Content, Media, Comments, Orders, Forms) from site plumbing (Tools: Email Log, Activity Log, Snippets, Redirects, Backups, and any future surface family by default), and Extensions joins Manage. Group labels collapse and expand with the choice remembered, every row keeps its icon, and third-party surfaces can claim Workspace with a group descriptor key when they are genuinely inbox-shaped; everything else lands in Tools so the prime real estate stays curated.
  • Plugin toggle refresh: activating or deactivating a plugin re-polls surfaces, builders and editor insertables so the sidebar and slash menu match live state without a hard reload.
  • Comments nav: hidden when comments are disabled site-wide; detection uses support / REST mechanisms rather than a single plugin slug.
  • History card: labels when a version was superseded; hides the live-post mirror; refreshes after save; site-timezone dates no longer skew.
  • Activity detail chrome: drops the redundant "Open in log" meta chip (footer open-in-provider remains).
  • User email template: site-branded only (no Minn Admin header/footer credit).

Fixed

  • Spam page tracks plugin toggles: activating or deactivating a spam plugin from Extensions now refreshes Settings → Spam in the same session; the cached settings data used to survive the toggle until a hard reload.
  • wrapperText fields no longer double-render: a block-form wrapperText pattern and the generic text-run pass both offered the same string, so the labeled field appeared alongside a duplicate "Text" run and the two edits raced. The labeled field now wins; overlapping runs are suppressed.
  • Sidebar scrolls on short screens: the navigation list scrolls when the window is short; the logo, search and your account stay pinned.
  • Details no longer breaks the editor: free contenteditable <details> trapped the caret and blocked typing after insert; Details is an island with trailing affordance and Remove + undo.
  • Basics list completeness: Spacer, File, Shortcode (and Embed/Gallery) always appear in Browse all / Basics even on classic content.
  • ⌘Z restores removed islands: while the "Block removed" toast is up, ⌘Z / Ctrl+Z runs the same restore as the Undo button (island deletes are outside Blink's undo stack).
  • New → Post/Page from the editor: URL changed to /editor/pages but the open post stayed on screen. Route change now compares editor type + id and rebuilds a blank document.
  • Relative times ("in 4h" on EDT): bare UTC timestamps (Code Snippets modified, Stream/WSAL/Aryo, GF entry dates, Redirection last hit, Simple History date_gmt) were parsed as site-local. normalizeTimeInput honors utc / *_gmt; adapters emit Z or set column utc: true. Site-local WP REST dates unchanged.
  • Otter Product Review / classic blocks no longer preview as giant stars: Otter only registers front-end style.css handles when has_block() runs on a real post, so island do_blocks never loaded them. The Otter adapter now registers those styles from the submitted markup (and returns their URLs) so review stars, pros/cons, and the rest layout at real size.
  • Otter Maps preview is no longer an empty shell: the Leaflet block is a JS-only empty div (and Otter can emit invalid height:400pxpx). Previews now use OpenStreetMap's embed iframe (Otter's own AMP path) so the map is visible without running Leaflet in the editor.
  • Slash menu on blank posts: empty editor bodies (new pages, select-all + delete) left the caret in a bare text node with no wrapping <p>, so typing / never opened the block menu. Blank bodies now seed a paragraph, and a bare text / is promoted to one on the fly.
  • Block editor ↗ saves first: the inspector (and locked-mode) escape to wp-admin now persists the live document before opening, so unsaved islands no longer vanish in Gutenberg. The button reads Saving… while the request runs.
  • ⌘S in shortcode (and other live-field) islands: focus in a shortcode input used to stop keydown propagation, so ⌘S never hit Minn and the browser offered "Save Page As…". Save is handled in the capture phase and commits the focused field first.
  • Backspace/Delete arm-then-remove is consistent: empty shortcode fields, empty code blocks, and islands all share the same first-press red outline / second-press remove (with Undo). Empty paragraphs no longer jump over a shortcode into the previous code block.
  • Featured image thumb is clickable: opens the media preview modal (full image, title/alt, Copy URL, Open, Edit image). From that context, Replace featured and Remove featured are available; saving an edited copy adopts it as the new featured image.
  • Self-update reloads the app: updating Minn Admin from Extensions (single or Update all) hard-reloads the page so the version badge, boot payload, and new JS/CSS land immediately instead of leaving a stale SPA in memory.

v0.9.0 - July 9, 2026

The block-library release. Minn grows past the curated slash menu: auto-insert for standalone third-party blocks, Stackable / Kadence / GenerateBlocks free design libraries, site patterns, and a Browse all (⌘/) picker. Complex islands gain text and image editing, previews that actually warm their CSS, and no more mid-card clipping. Table structure undoes with ⌘Z; entry details step with ←/→.

Added

  • Third-party blocks insert with no adapter: dynamic (server-rendered) blocks a plugin registers now appear in the editor's slash menu automatically, provided they prove they render standalone: each candidate is render-probed, and blocks that output nothing from a bare comment (hybrids whose real markup lives in their editor JS) are excluded rather than inserted broken. Entries are search-only, so the default menu stays curated; type part of a block's title, or its namespace (like /anchor) to list everything a plugin ships. Insertion lands as a configurable island with a real preview and the schema-driven inspector, exactly like adapter-declared blocks. Adapter insert templates still win when present, insert => false hides a block, and the new minn_admin_insert_blocks filter prunes or extends the list.
  • Swap the images inside any complex block: the inspector now shows an Images section listing every picture an island uses, whether it sits in an img tag or a background style. Replace opens the media picker (upload straight into it if the shot isn't in the library yet), and the new image lands everywhere the old one appeared, with paired media ids and wp-image classes retargeted so the block editor agrees. Anything typed into the inspector's other fields rides along with the swap.
  • Edit the text inside any complex block: the block inspector now lists every piece of text living in an island's saved HTML as an editable field, no matter how deeply the block nests and even when the block registers no editable settings (the Stackable case). Each field writes back only the exact text you changed; everything else in the block stays byte-identical, so nothing ever breaks in the block editor. Inserting a design opens the inspector right away so the placeholder copy can be replaced on the spot.
  • Stackable design library in the slash menu: Stackable's blocks are built in its editor JS, so Minn can't create them one by one; instead, Minn now scrapes what Stackable itself publishes as data. All 107 free designs from the Design Library (Hero, Call to Action, Pricing Table, Testimonials, and more) surface as search-only slash entries; try /hero or /pricing. Each design inserts as one island of the library's own serialized markup, valid in Gutenberg by construction, with its stock images sideloaded into the media library first. Requires Stackable to be active; nothing loads otherwise.
  • Design-suite previews got their CSS back: three more preview fixes from the block-suite lab. GenerateBlocks previews now carry each block's own styles; Otter previews (including the new atomic-wind Tailwind blocks) recover the per-post CSS the plugin already cached, so an icon renders at icon size instead of filling the canvas; Essential Blocks previews extract the CSS each block carries in its own markup. Under the hood the preview scoper also learned modern CSS: @layer-wrapped stylesheets (compiled Tailwind) and nested rules now scope correctly instead of being dropped. Adapters can feed preview styles via the new minn_admin_render_styles filter.
  • The block picker (⌘/): with hundreds of insertables now available, the / menu grew a door. "Browse all" at the bottom of the slash menu, or ⌘/ anywhere in the editor, opens a large searchable picker with everything grouped by source: Basics, each plugin's blocks, each design library, and patterns. Picking inserts exactly like the slash menu would, at your caret. The inline / menu stays curated and fast.
  • GenerateBlocks pattern library in the slash menu: all free GenerateBlocks patterns join the block library through the plugin's own cached proxy, with their per-block CSS traveling inside the markup so previews arrive fully styled. Entries wear a generateblocks badge; remote images are sideloaded on insert like every design source.
  • Kadence design library in the slash menu: all 352 free Kadence sections join the block library, fetched through Kadence's own caching proxy (no license needed) and inserted as preserved sections with live previews, editable text, and replaceable images; remote images are sideloaded into the media library first, like every design source. Search by section name; entries wear a kadence badge.
  • Previews warm themselves: some plugins only produce their CSS when a page runs in a browser (Otter's atomic-wind compiles Tailwind client-side, and clears its cache on every save, so an actively edited post is usually cold). When the server reports that gap, Minn quietly loads the page in a hidden iframe so the plugin's own compiler runs and caches, then picks the styles up for its previews. No more giant unstyled icons after a save.
  • Fresh assets after every update: script and stylesheet versions now include the file's timestamp, so the browser never serves a stale copy of the app after an update or during development.
  • Block settings that scale: design-suite blocks can register hundreds of settings (one popular post grid ships 315). The inspector now keeps the fields a block actually uses in view and tucks the rest behind "More settings" with a filter box; setting a value promotes that field into view. Small blocks are unchanged.
  • Image replacement understands more plugins: swapping an image inside a complex block now retargets attachment ids across every convention found in the block-suite lab (Kadence's background pairs, media objects, GenerateBlocks' media ids, and per-image markers from Otter sliders) so the block editor and front end always agree on the new image.
  • Friendlier block settings labels: inspector fields fall back to humanized attribute names ("Has custom CSS" instead of hasCustomCSS) when a plugin doesn't provide labels.
  • Block patterns in the slash menu: every pattern registered on the site (by core, the active theme, or plugins like Otter and Essential Blocks) is now insertable from the editor, no adapter needed. Patterns are ready-made valid markup, so they land as preserved sections with live previews, editable text, and replaceable images; a multi-section pattern becomes a run of siblings, and its plain paragraphs turn into normal editable prose. Search-only like the rest of the block library; contextual patterns (query variations, template parts) are filtered out, and post-type-restricted patterns only show where they apply.
  • Block editor escape hatch on every island: the inspector's action row now links straight to the post in the block editor. Content lives in Minn; layout, spacing, and color controls live where the block's own tools are.

Improved

  • ←/→ steps through entry details: when viewing a Gravity Forms entry (or any surface detail opened from a list), the left and right arrow keys go to the previous and next item on the current page, with matching ‹ › buttons in the modal header. Same idea as the media preview; arrow keys leave the caret alone when you're typing in a field.
  • Widget drag grips: widget rows in an area get the same drag handle as menu items. Drop above or below another row to reorder; ↑↓ and Move to… stay for the other cases.

Fixed

  • Island previews no longer clip tall blocks. Previews had a hard max-height: 420px with overflow hidden, so multi-card grids (e.g. Anchor Blocks vector-cards) and tall design inserts were cut off mid-card in the editor while the front end looked fine. The cap is gone; the island grows with its content.
  • X embeds read correctly in dark mode. Island previews can't run Twitter's widgets.js, so they show the bare blockquote fallback (always a light card before). It now uses Minn design tokens (dark panel on dark theme, soft gray on light). The site's body background is no longer painted onto the island shell either (that was the remaining white plate under the card).
  • Table row/column actions undo with ⌘Z. Add, delete, header toggle, and delete-table used to mutate the DOM directly, so ⌘Z was a no-op (deletes only offered a short-lived Undo toast). Those ops now go through the browser command stack: mutate a clone, swap via insertHTML / delete, and ⌘Z restores the previous table. Destructive ops still toast a "⌘Z restores it" hint.
  • Adding a column/card to a complex block clones a sibling. "+ Add" used to create an empty block comment, which renders nothing and fails block-editor validation for design-suite blocks. It now duplicates an existing sibling verbatim (plugins like Stackable regenerate duplicate ids themselves), which is what "add another card" means anyway. Attribute-only children keep their blank start.
  • Complex-block previews now pick up lazily-loaded styles. Many block plugins (Stackable with its CSS optimizer, Kadence, GenerateBlocks) only enqueue their stylesheets while one of their blocks renders, so island previews could show bare unstyled markup. The preview renderer now reports what the render enqueued and the editor scopes it in, and the editor-styles sweep also fires the front-end registration hooks it was missing.
  • New posts no longer degrade to classic mode. Reloading a brand-new post before its first content save (the title-only autosave draft) reopened it as a classic-mode post permanently, silently hiding embeds, galleries, and custom blocks from the slash menu. Empty posts now open in blocks mode; there is nothing classic mode would need to preserve.

v0.8.0 - July 6, 2026

The delight release. Horizon 2 of the editor roadmap lands: revision diffs, an outline panel, focus mode, and an internal link picker, plus two new view modes and a real keyboard-shortcut story. Around the editor, the whole app picked up a shared context-menu language (content rows, media, comments, tables), Minn grew its own image editor, and the System page now surfaces the silent-rot trio every developer checks first.

Added

  • Revision diffs: the History card opens a side-by-side diff of a revision against your current content (unsaved edits included) with word-level change marks, instead of a raw preview. Unrelated paragraphs render as a removal plus an addition, not one fully-marked change; identical revisions say so; Restore is unchanged.
  • Outline panel: headings as a clickable table of contents in the editor sidebar. It updates live while you type, indents by depth, sticks in view on long posts, and clicking a heading scrolls to it with a highlight that rides the scroll.
  • Focus mode (⌘⇧D): fades everything but the paragraph you are writing, with typewriter scroll and the nav and sidebar tucked away. Persists per browser; never touches saved markup.
  • Outline mode (⌘⇧O): just the writing and the outline. Hides the nav and every sidebar card except the Outline. The two view modes are mutually exclusive and live in the ⌘K palette.
  • Internal link picker: type a post title into the link popover (⌘K with text selected) and pick from your own content; URLs still paste straight through.
  • Image editor: rotate and crop right in the media preview, saved as a new copy through core's own image-editing endpoint. All pixel work happens server-side; originals are never touched.
  • Context menus everywhere: right-click a content row for quick status changes, view/preview, a block-editor escape, and trash; a media item for preview, copy URL, edit image, and delete; a comment for its moderation verbs; a table cell for targeted row and column operations.
  • Keyboard shortcuts: ⌘. shows or hides the navigation, ⌘⏎ publishes or updates, ⌘S saves, and the help dialog now documents the whole set.
  • Audit-log adapters: WP Activity Log, Activity Log (Aryo), and Stream join Simple History, so all four major audit plugins read natively in Minn.
  • System page additions: an autoloaded-options breakdown with the top offenders and a health check, cron health (overdue events flagged), expired-transient bloat, and a clickable version badge that opens the full changelog.
  • Themed date-time picker: scheduling gets a Minn-styled calendar with a lenient time field and an explicit Done, replacing the unstyleable native control.
  • Menu drag handles: drag to reorder menu items; children travel with their parent. The indent buttons stay for nesting.
  • Extensions cards: real wp.org plugin icons (linked to the plugin's directory page) and author lines linked to the author's site.

Improved

  • Content lists sort by publish date, so scheduled posts lead with the dates they go out. Rows grow a hover actions button; the big Overview stat cards navigate to their views; sites without comments show a Users count instead of an eternal zero.
  • Sidebar cards collapse from their titles and remember your layout; the role pickers in Users and the profile are searchable comboboxes; the WordPress and PHP marks on the System page are the real brand icons.
  • Deactivating Minn from Extensions asks properly and lands you on a readable notice before the classic dashboard, instead of a native confirm and an instant redirect.
  • Every block-config popover (island, table, image, code) now opens beside the block instead of on top of the content it configures, and the code block's settings chip is persistent like table and image chips.

Fixed

  • The block inspector can now edit the text of core paragraph and heading children inside wrapper blocks (the report-card case), and no longer injects empty attributes into children it merely displayed.
  • Applying a link deep in a long post no longer scrolls to the top; the same fix covers image drops, slash commands, and focus-mode toggles.
  • Toggling a plugin no longer scrolls the Extensions list to the top (the tab bar's reveal was yanking every scroll ancestor).
  • A code block as the last block no longer traps the caret; a click-to-continue paragraph always follows terminal blocks, tables, and embeds.
  • The activity feed decodes entities, labels untitled drafts, and no longer hides never-edited drafts; the version badge shows the full version.

v0.7.1 - July 5, 2026

A fast follow for managed hosts: the new System page could 500 where wp-admin includes were not preloaded.

Fixed

  • System page 500 on managed hosts: the System endpoint called disk_free_space() / disk_total_space() unguarded — hosts like Kinsta remove them from the web PHP via disable_functions, which turns the call into a fatal error (@ doesn't save you, and the CLI on the same box reports nothing disabled). Both are now function_exists()-guarded, as is php_uname() a few lines below — the next fatal waiting on hardened hosts. Disk usage degrades to "Unknown" where the host hides it.

v0.7.0 - July 5, 2026

Beyond writing. Two big moves this cycle: coexist with page builders instead of pretending they don't exist, and give developers a real System page. Plus the trust work that closes Horizon 1 of the editor roadmap — a writer never loses work.

Added

  • Page-builder coexistence: Minn detects pages built with Divi, Elementor, Brizy, Beaver Builder, Etch, Bricks or WPBakery and gets out of their way. A builder chip marks them in the content list; opening one shows a read-only preview with an Edit in ⟨builder⟩ button to the builder's own chrome-free surface (no wp-admin screen), while title, status, URL, SEO and the sidebar still save from Minn. Builders that keep their content in postmeta (Elementor, Beaver, Brizy, Bricks) or shortcodes (WPBakery, legacy Divi) fence the editor so a stray Minn edit can't silently break their canvas; block-native builders (Etch, Divi 5) stay editable through islands. Third parties register via the minn_admin_page_builders filter.
  • New page in a builder: The + New menu lists every active builder — pick one and Minn creates a prepared draft and hands the tab straight to the builder's editor.
  • Paste cleanup: Pasting from Word, Google Docs or any web page is sanitized to Minn's safe block subset — Word's mso-list paragraphs rebuild into real nested lists, Docs style-spans map to bold/italic/strike/code, javascript: hrefs and vendor styling never pass, and a single ⌘Z reverts a whole paste. Multi-line plain text becomes real paragraphs; a lone URL still becomes an embed. Classic mode is sanitized too.
  • Inline media flow: Paste a screenshot or drag an image file into the editor and it uploads to the media library at the caret — an instant preview, then an undo-safe swap to a real attachment (a true Gutenberg image block). The serializers skip in-flight uploads so an autosave can never store a blob: URL. Every editable image now carries a typable caption ("Write a caption…").
  • Conflict safety: Post locking rides WordPress's own _edit_lock, so Minn, the classic editor and Gutenberg all honor each other. Opening a post someone else is editing shows a takeover dialog; being taken over drops you to read-only with a "take back" banner. A localStorage crash net snapshots every edit within ~1.2s — even before the first autosave — and offers recovery on the next open, so a crashed browser loses nothing.
  • Undo for structural deletions: Deleting an embed, gallery, table row/column or whole table shows a "Removed — Undo" toast. (These are direct-DOM operations outside the browser's undo stack, so ⌘Z can't reach them — see the undo-completeness investigation.) Restoring re-inserts the block and its saved markup intact.
  • Editor sidebar — the publish essentials: Editable permalink/slug, per-post Discussion (allow comments / pingbacks), full Visibility (Public / Password protected / Private) and Sticky for posts — everything writers used to open wp-admin for. All through WordPress's native REST fields, with the sticky/password mutual exclusion and "private is a status, not a field" edge cases handled so an autosave never accidentally publishes a draft.
  • System page: A developer diagnostics surface under Manage — a health strip (PHP version, HTTPS, persistent object cache, memory, OPcache, debug-in-production, uploads writable) over cards for WordPress, PHP, the database (with a largest-tables breakdown) and the server, plus one-click Copy report as markdown. Deliberately not WordPress-y — dense with the facts a developer actually wants.
  • Debug tools: On the System page, live toggle switches for WP_DEBUG, WP_DEBUG_LOG, WP_DEBUG_DISPLAY, SCRIPT_DEBUG and SAVEQUERIES that safely rewrite wp-config.php — whitelist-only, syntax-validated before writing, backed up, and shown only when wp-config is writable and file mods aren't disabled (constants defined elsewhere are read-only). The debug.log path is clickable and opens a large overlay showing the tail with Refresh / Copy / Clear.
  • Installed extensions manifest: The System page lists every plugin (active first, inactive dimmed), must-use plugin and theme with versions — folded into the Copy report too.
  • Extensions filters & search: The Extensions view gains All / Active / Inactive / Updates status filters and a search box.
  • Test coverage: New repo-citizen Playwright suites for paste cleanup, conflict safety, the crash net, inline media, the editor sidebar, the System page and structural-deletion undo — each verifying saved content, not just the DOM.

Improved

  • One consistent grammar for list-view toolbars: filters and search on the left, a single primary action on the right, and the item/page count moved down to the pager where it belongs. Trash became a slice tab rather than an action button.
  • The page-builder chip moved to the slug line so its placement is consistent regardless of the builder's name length, leaving the Status column a clean column of pills.
  • Content-list and + New row markers are proper SVG icons now (the page glyph read as broken).

Fixed

  • The Extensions on/off switch reflects the real plugin state immediately. Concurrent loadPlugins() fetches could replace the cache after a render had bound the toggle handlers to the older array, so the switch appeared frozen even though the plugin had toggled server-side.
  • A late editor re-render could revert unsaved edits before a save (surfaced under server load) — the editor now adopts the live DOM whenever there are unsaved changes.
  • Etch's edit URL renders its app at the site root (?etch=magic&post_id=N); a permalink-based URL yielded a silent blank page.
  • Toasts animate straight up from the bottom instead of flashing in sideways — the keyframe was dropping the horizontal-centering transform mid-animation.
  • A first-block island's ⚙ chip is no longer clipped at the top of the editor (overflow-x: hidden was forcing vertical clipping to auto).

v0.6.0 - July 5, 2026

The editor release. Everything here is aimed at one goal: writing in Minn beats writing in the block editor — see the new editor roadmap.

Added

  • Markdown typing conventions: the full set — ` code , bold, *italic*, __bold__/_italic_ (word-boundary, so snake_case survives), ~~strike~~, text; block prefixes on space — #######, -/*/+, 1., > — plus ` → code block and --- → divider. Wraps go through the undo stack so ⌘Z restores the literal text, with guards so spaced math stars and array0` prose never convert.
  • Inline code: a </> toolbar toggle and the backtick markdown rule, plus a boundary escape — typing at a code chip's edge lands outside the chip (contenteditable offers no such caret position; Chrome would extend the code forever).
  • Link popover + ⌘K: click any link to edit its URL, open it, or unlink. The toolbar button and ⌘K-with-a-selection create links; ⌘K still opens the command palette everywhere else.
  • Table controls: every editable table carries a persistent ⚙ chip opening a popover — add row above/below, add column left/right, delete either (all relative to the caret cell), make the first row a header (content-preserving both directions), delete table. Tables wear the same dashed cutout as block islands, with editor-side gridlines and a shaded header row.
  • Image controls: images get the island-style cutout and their own persistent ⚙ chip into the existing alt/caption/replace popover. Removing an image is dialog-free and ⌘Z restores it.
  • Status-aware autosave: 15s-idle / 60s-max instead of every keystroke. Drafts save in place; published, scheduled and private posts are never written by autosave — edits back up to a WordPress autosave revision (like Gutenberg) and apply only on Update. Save draft button, ⌘S, an unsaved-changes indicator, flush-on-navigate and a browser unload warning.
  • Backup restore: opening a post with a newer autosave revision (a crash, an abandoned session) shows a banner offering Restore / Dismiss. REST saves now refresh the post's oEmbed caches — core only does that from the classic editor, so stale embed failures used to stick forever.
  • Text alignment: center/right toolbar toggles, and aligned paragraphs/headings now round-trip as editable content instead of becoming read-only islands. Ordered-list start/reversed/type round-trip too, and core/spacer height edits regenerate the block properly.
  • Front-end styles in previews: island previews load the site's real block and theme CSS — collected server-side, scoped client-side so the admin chrome and the typing surface keep Minn's own look. An anchor/stats-dashboard island now looks like the published page.
  • In-place embed & gallery editing: the inspector offers Change URL… / Replace images…, rebuilding the block through the same templates that create them. The misleading generic attribute fields are gone (editing url in the comment never touched the URL living in the saved HTML). Embed islands now render the real embed in the editor.
  • Word count · reading time: a fixed bottom-right pill, always visible while scrolling, recounted live (including when island previews finish rendering).
  • SEO editor panel: Yoast SEO or Rank Math — SEO title, meta description and focus keyword in the editor sidebar, via a dedicated minn_seo REST field (edit-context only, per-post capability checks). Completes the extension-api plan.
  • Gravity Forms, readable: the entry detail is now a document — answers under the form's real field labels in form order (choice labels resolved, composite names assembled, multiline preserved), then a Submission section (formatted date, clickable source, IP, user), and an open-in-GF link. A new Forms view lists forms with entry counts and status, offers activate/deactivate and edit-in-GF. Deliberately not a form builder.
  • x.com embeds: WordPress 7.0's trusted oEmbed providers cover twitter.com but not x.com, so tweets were stripped as untrusted — Minn registers the x.com provider until core catches up.
  • Browser test harness: self-contained Playwright suites in tests/ (markdown rules, autosave semantics) plus a CLAUDE.md agent guide. Suites create and delete their own fixtures over REST and gate on zero console errors.

Improved

  • SVG icons across the editor toolbar and slash menu (the app's lucide-style set), plus new strikethrough, bulleted/numbered list and clear-formatting buttons.
  • The editor toolbar is sticky, and block-type buttons toggle — pressing Quote or H2 again returns to a paragraph. (Repeat presses used to be silent no-ops that still pushed junk undo entries, which made ⌘Z look broken.)
  • The slash menu filters as you type — /co narrows to Code; a second / (a literal path) dismisses it.
  • Table and image chips highlight together with their cutouts on hover, track scrolling, and are always visible — no hover hunting.
  • Surface framework: collections can declare a second manage view, sectioned detail routes, conditional (when) and link (href) actions — all generic, first used by Gravity Forms.

Fixed

  • Backspace in the paragraph after an embed no longer destroys the embed (Chrome treats an adjacent island as one deletable atom — and merged the neighbors too). Empty blocks delete alone; deleting into an island arms it red and a deliberate second press removes it.
  • Images insert at the caret instead of the top of the document — clicking in the media picker destroyed the editor selection.
  • Alignment now previews inside the editor; the word count is no longer stale until the first keystroke.
  • Serialized content stays clean: no nbsp litter around inline elements, <strike> stored as <s>, lists never nest inside paragraphs, hover styles and image-delete husks never reach the database.
  • Gravity Forms surface now appears for administrators whose role has gform_full_access but not the granular caps (gated through GF's own capability resolver).

v0.5.0 - July 4, 2026

The breadth release. The everyday rooms of wp-admin land in one sweep: taxonomies, Menus, Widgets, Trash, comment replies, media search and filters, excerpts, page attributes, Your profile and real pagination, plus core WordPress updates and the option to make Minn the default admin. The editor learns embeds, galleries, video and audio blocks, and image controls; redirects can be created and searched; Query Monitor gets a chip on every Minn page.

Added

  • Taxonomies manager: The Post Types view gains a Taxonomies tab — every registered taxonomy with its attachments, term counts and owner, editable through the same storage adapters as post types (ACF acf-taxonomy definitions via ACF's own API, Custom Post Type UI's option, or Minn's own store). Create (hierarchical or flat, choose the backend), re-attach to any post types, or remove — terms always stay in the database, and ACF deletions trash recoverably. Core and code-registered taxonomies are read-only. The Post Types modal's taxonomy checkboxes are now dynamic — every assignable taxonomy, not just Categories/Tags.
  • Create redirects (and search them): The Redirects surface gains an Add redirect button — a form for source, target and HTTP status that writes through Redirection's own API — plus a filter box that searches by source URL server-side. Both come from two new generic surface capabilities (create and search), so any adapter can opt in.
  • Tidier surface tables: Columns take an explicit width and a num format (right-aligned, tabular); text cells truncate to one line with an ellipsis instead of wrapping long URLs to three rows, and empty/zero timestamps read "—" rather than "Invalid Date". Redirects now fit source, monospace target, code, hits and last-hit cleanly on one row.
  • More redirect plugins: Drop-in adapters for Safe Redirect Manager and Simple 301 Redirects — list, search, create and delete, each shimmed over the plugin's own storage (SRM's srm_* functions; the 301_redirects option) since neither exposes REST.
  • Image controls: Clicking an image in the editor opens a popover — alt text, caption (created, updated or removed, wrapping bare images in the standard figure), Replace via the media picker, and Remove. Replacing keeps the block honest: the {"id":…} attribute and wp-image-N class follow the new attachment, and stale srcset/sizes/dimensions are dropped.
  • Video & audio blocks: core/video and core/audio join the editable set via attribute passthrough — no longer islands.
  • Query Monitor support: With QM active, Minn's pages get the full Query Monitor experience — a floating summary chip (time · memory · query time · query count) that opens the real QM panel, covering the Minn document request. The integration is a bundled adapter plus minn_admin_template_footer, the one hook Minn's standalone document now fires (deliberately not wp_footer — no third-party injection). Capability checks stay QM's own: users without view_query_monitor get zero QM bytes.
  • Attribute passthrough for simple blocks: Images, tables, quotes, separators, verse and preformatted blocks that carry attributes ({"id":…,"sizeSlug":…} images, styled tables/quotes/separators) are now fully editable instead of islanded — the comment attributes are parked on the element and re-emitted byte-faithfully on save, with Gutenberg's comment-safe escaping. The class-derived hasFixedLayout respects explicitly-written false (newer Gutenberg defaults tables to fixed). Only non-text-flow blocks participate, so contenteditable splits can never duplicate attributes. Cosmetic note: void elements serialize as <img …> rather than <img …/> (HTML-equivalent).
  • Activity chart drill-down: The Overview's activity bars are clickable — a modal lists the events behind the bar (posts and pages published, comments received in that day or week), each row linking to the editor or the Comments view. The overview endpoint now stamps each chart bucket with its GMT bounds, and a new overview/activity endpoint returns the events for a window.
  • Trash: The Content view gains a Trash toggle — see trashed posts, pages and custom post types, restore them (a new posts/{id}/restore endpoint; core REST has no untrash) or delete them permanently, singly or in bulk. Authors see only their own trashed items, matching wp-admin.
  • Menus: A full navigation manager for classic themes (block themes keep the site editor, matching wp-admin) — every menu as a tab, items in their real hierarchy with reorder/indent/outdent controls, inline label and URL editing, add pages/posts via a searchable picker or custom links, theme-location assignment via combobox, and create/rename/delete menus. All through core's wp/v2/menus, menu-items and menu-locations REST — reordering renumbers the whole tree and writes only the items whose order or parent actually changed.
  • Widgets: Classic widget areas as cards — reorder within an area, move between areas, delete, and edit block, text and HTML widgets in place (other widget types keep their settings and can still be arranged). Adding drops in a block widget and opens the editor. Widgets are created and then assigned to their area in a second request — creating straight into a sidebar gets silently swept to inactive by the same request's retrieve_widgets() pass (core #53657 territory).
  • Page attributes in the editor: Pages (and hierarchical post types) get a Page attributes card — a parent picker showing the page tree with the post's own descendants excluded, a template combobox (a new templates endpoint exposes the theme's classic Template Name: templates, which core REST validates against but never lists), and a menu order field. Everything rides the normal autosave. The card appears only when the post type actually supports something: posts see nothing unless the theme registers post templates.
  • New menu: The + New button opens a Post / Page choice (page authors only — everyone else goes straight to a new post), and the ⌘K palette gains "Create new page". New pages get the full Page attributes card before first save, so parent and template can be set as you write.
  • Embeds: Paste a lone YouTube / Vimeo / TikTok / Spotify / X link (any of fifteen core oEmbed hosts) into an empty block and it becomes a core/embed island; the slash menu gains an Embed command that takes any URL. The markup is Gutenberg-byte-faithful (verified with a parse_blocks/serialize_blocks identity round-trip), so the block opens natively in the block editor. URLs inside sentences still paste as plain text, and classic-mode content keeps relying on WP's own autoembed.
  • Galleries: A Gallery slash command opens the media picker in multi-select — pick images in order (or upload straight into the selection) and insert a modern nested-image core/gallery as an island, rendered in place. Editing an existing gallery still hands off to the block editor; creating one no longer does.
  • Core WordPress updates: When a core update is on offer, Extensions leads with an update banner — one click runs the same Core_Upgrader path as wp-admin (maintenance mode, rollback protection), then triggers the database migration step over loopback. Update notifications now land on Extensions instead of bouncing to wp-admin. Gated on update_core.
  • Minn as the default admin: A new General setting — after signing in, users who can use Minn land at /minn-admin/ instead of the wp-admin dashboard. Explicit redirect_to deep links (a plugin page, a specific post) still go where they intended, users without edit_posts keep core behavior, and classic wp-admin stays fully reachable.
  • Comment replies: Answer comments without leaving Minn — a Reply box on every pending and approved comment, posting as you. Replying to a pending comment approves it, matching wp-admin.
  • Media search & filters: The library gains a search box and type tabs (Images / Video / Audio / Docs) — server-side via the media endpoint's own search and media_type params, so it scales past the 48-per-page window.
  • Excerpt: Posts (and CPTs with excerpt support) get an Excerpt field in the editor's Settings card, riding the normal autosave.
  • Your profile: The sidebar account area (and a new ⌘K entry) opens your own profile for any role — display name, email and password, with the role shown read-only when you can't change it. Non-admins finally get a way to update their password without wp-admin; the page reloads after a self password change since the session token (and REST nonce) rotates. A self display-name edit updates the sidebar immediately.

Improved

  • Real pagination: Every list view — Content, Media, Comments, Orders, Users and all adapter surfaces — replaces the append-only "Load more" button with numbered pagination (‹ 1 … 4 5 6 … 20 ›) plus a "page X of Y" count, jumping back to the top on page change. Content's type tabs now filter server-side (each tab is its own query instead of a client-side sieve over merged pages), which also makes them accurate on large sites. The wp.org install dialogs keep "Load more", where appending suits browsing.
  • Editor says what it's editing: The topbar pill reads "New page" / "Post · Published" instead of a bare status, and the title placeholder follows suit ("Untitled page") — a blank new page and a blank new post are no longer indistinguishable.
  • Add-plugin dialog: wp.org search results paginate — a "Load more" row appends the next page (with the running count of 2,500-odd results) instead of stopping at twelve, keeping your scroll position instead of snapping back to the top. Plugin-name cleanup handles more tagline junk: attached colons ("UpdraftPlus: WP Backup & Migration Plugin"), sentence periods ("CleanTalk Anti-Spam. Spam Firewall…"), comma lists ("SmartCrawl SEO checker, analyzer & optimizer") and "by Vendor" suffixes — the vendor only comes off when a multi-word name remains, so "Login by Auth0" survives while "GEO Plugin by Squirrly SEO" trims. The untouched full name stays as the row's tooltip, and the same cleanup already runs across the Extensions list.
  • Swappable overview chart: When an analytics adapter provides traffic, the chart no longer hides the Activity view — a ⇄ button in the chart header swaps between Traffic and Activity (with its clickable drill-down bars), and the choice sticks across visits. Recent activity trims to four entries so the two dashboard cards line up.
  • Searchable Forms and Activity Log: The Gravity Forms surface gains a filter box that searches every field of every entry (per-form tabs included), and Simple History's Activity Log gets free-text event search — both server-side through each plugin's own REST API. Gravity Forms takes its search criteria as a JSON string, so the generic surface search capability now accepts a JSON-criteria form alongside the plain {q} query template — any adapter can use either.
  • Revision authors: The editor's History card now shows who made each revision. (Revisions expose an author ID but no embeddable link, so names resolve through the users endpoint — the previous _embed approach could never work.)
  • Tag autocomplete: The editor's tag input uses the combobox — click to browse existing tags with usage counts, arrow/click to pick; plain Enter still creates exactly what you typed as a new tag.
  • Site icon as favicon: Minn's pages now use the site icon (settable from Minn's own Settings) as their favicon when one exists.

Fixed

  • Stale content loads: A content request still in flight when the filter context changes (trash toggled, search typed, taxonomy picked) is now discarded instead of landing rows from the old context into the new view — which in trash mode could have decorated live posts with Restore/Delete-permanently buttons.

v0.4.1 - July 4, 2026

A fast follow: per-plugin updates could deactivate the plugin they updated.

Fixed

  • Per-plugin updates deactivated active plugins: The single-plugin update endpoint used Plugin_Upgrader::upgrade(), whose core behavior deactivates an active plugin before swapping files and leaves reactivation to the caller — so updating an active plugin from Minn (including Minn itself) stranded it deactivated. Now uses bulk_upgrade() for a single file, the same path core's own AJAX updater uses, which preserves active state — plus a reactivation safety net. "Update all" was never affected.
  • Plugin description punctuation: dropped the em dash ("Fast, focused and beautiful. Served at /minn-admin/.").

v0.4.0 - July 4, 2026

The block-inspector release. Complex blocks stop being sealed boxes: every island gets a settings form drawn from the block's own registered schema, children can be added, removed and reordered, custom blocks insert from the slash menu, and previews render with real markup. A Post Types manager arrives alongside AnalyticsWP traffic, the site icon, searchable selects and timezone autocomplete.

Added

  • Block inspector: Complex blocks (islands) are no longer opaque. Every island's chip is now a ⚙ button that opens an inspector popover: the block's attribute schema is fetched from wp/v2/block-types, a form is generated from it (strings, numbers, booleans, enums), and edits rewrite the attributes JSON in the block comment — Gutenberg-escaped, spliced back verbatim, byte-safety model unchanged. Works one level deep too: nested self-closing children (e.g. Anchor Blocks conversation messages) each get their own form section. Attributes stored in saved HTML (source-backed) are correctly left alone.
  • Add, remove & reorder children: When an island has the standard InnerBlocks shape (wrapper HTML + block children), each child section in the inspector gains ↑ ↓ × controls and a "+ Add" button — insert a new message/card/row with schema defaults, reorder, or delete, then Apply. Typed-but-unapplied values survive the re-renders; islands with real HTML interleaved between children keep attribute editing but lock structure changes.
  • minn_admin_block_forms filter: Plugin authors can refine the inspector's generated forms — per-attribute labels, controls (text · textarea · select · number · checkbox), option lists, hiding, and field order — plus wrapperText patterns that surface editable text living in an InnerBlocks wrapper's saved HTML (replaced in place only when changed, so untouched wrappers stay byte-identical). The convention: ship the integration inside your own plugin — the filter is a no-op without Minn. Anchor Blocks is the reference (app/MinnAdmin.php), covering all 13 of its blocks including a user/assistant Role select and the editable conversation header.
  • Code block config chip: Editable code blocks get the same ⚙ affordance islands have — hover (or place the caret) and a floating chip shows the current language; click it for a popover with the syntax-highlighting picker. Lives outside the editable document, so it can never leak into saved content.
  • Insert custom blocks from /: Blocks that declare an insert template via minn_admin_block_forms appear in the slash menu — inserted as a configurable island with a real server-rendered preview and the inspector opened immediately. Anchor Blocks offers Conversation, Timeline, Callout, Stats Dashboard and Bar Chart; templates are verified byte-identical through core's own parse_blocks/serialize_blocks round-trip. Blocks-mode only, and the slash menu now scrolls when it grows.
  • Remove a block from the inspector: Every island's inspector now has a Remove action (with confirm) — including blocks that aren't registered on the site, where it's the only action. Previously the only way to delete an island was selecting the card and pressing backspace.
  • Post Types manager: A new Post Types view (Manage → Post Types) lists every registered post type — labels, slug, item counts, REST availability, and who manages it — and edits definitions through whichever manager owns them: ACF post types (written via ACF's own internal API, so they stay first-class in ACF's UI), Custom Post Type UI (its option, its shape), or Minn's own lightweight store when no manager plugin is active. Create (choosing the storage backend when several are available), edit labels/visibility/supports/taxonomies, or remove a definition — content is always preserved, and ACF deletions trash (recoverable) rather than delete. Code-registered types are shown read-only. Rewrites flush automatically and the Content view's type tabs update immediately.
  • AnalyticsWP traffic adapter: The Overview chart gains a fifth analytics provider — daily visitors (distinct sessions) and pageviews aggregated from AnalyticsWP's events table with the same site-timezone bucketing its own dashboard uses.
  • Real island previews: Islands render their actual content in the editor via a new minn-admin/v1/render-blocks endpoint (server-side do_blocks, edit_posts) — dynamic blocks and nested dynamic children show what the site will show instead of an empty "Dynamic block" card. Previews refresh live after inspector edits. Best-effort: a misbehaving render callback never breaks the editor.
  • Code block language attribute: core/code blocks carrying {"language":…} in the block comment (the attr dialect) are now fully editable instead of islanded — the existing toolbar language picker reads and writes the attribute, and serialization preserves the incoming dialect (attr stays attr, class stays class). markup added to the language list.
  • Site icon: Settings → General can now set the site icon — drag & drop an image, choose from the media library, or remove it, with a live preview.
  • More settings: Membership (anyone can register) and New user default role (General); Convert emoticons (Writing); Moderate all comments, Registered-users-only commenting and Show avatars (Discussion) — exposed over wp/v2/settings via register_setting, with role writes validated server-side.

Improved

  • Upload from the image picker: The Insert-image / featured-image picker gains a drag & drop zone (with click-to-browse) — drop an image and it uploads and is used immediately, instead of dead-ending when the library is empty.
  • Searchable Content filters: The Content view's category and tag dropdowns are now the searchable combobox too — type to filter a long term list, with usage counts and the theme-native panel instead of the OS select.
  • Searchable selects: New user default role, Default post category, and the Homepage/Posts-page pickers are now themed, searchable comboboxes — click to browse with the current choice highlighted, type to filter, and the display shows friendly labels while the real value is what saves. Unlike native selects, the option panel matches Minn's theme on every OS.
  • Timezone autocomplete: The Settings timezone field is now a proper combobox instead of a 400-option select — click to browse the full list (current zone highlighted), type to filter ("new york" finds America/New_York — spaces match underscores), arrow keys + Enter to pick. The option panel is anchored in-flow below the input, so it never drifts around the page the way the native datalist popup does, and free-typed input is validated against real zone ids before saving.

Fixed

  • Stale Overview after plugin changes: Activating, deactivating, installing or deleting a plugin now clears the Overview cache (and the post-type caches) — switching analytics plugins immediately switches the Traffic chart's provider instead of showing the old one until a hard reload.

v0.3.0 - July 4, 2026

The list-polish release. Filters arrive where they were missing (user roles, categories and tags), orders change status in place, media gets alt-text and title editing, content gains bulk actions, redirects become editable, and permalinks join Settings. Toolbars stop jumping, tab strips scroll, and the phone layout firms up.

Added

  • User role filter: The Users view gains role tabs (All plus every registered role), filtering server-side via wp/v2/users?roles=.
  • HTML email preview: The Email Log (Gravity SMTP) detail now renders the real HTML message in a sandboxed iframe — the email as it actually looks — in a wider modal, with Open raw (opens the message in a new tab) and Resend (re-dispatches to the original recipients) actions.
  • Category & tag filters: The Content list gains category and tag dropdowns (post taxonomies), and the editor sidebar gains a Tags box — add existing or brand-new tags inline (with suggestions), remove with a click — alongside the existing categories picker.
  • Order status changes: The order detail modal can set an order's status (processing, completed, on-hold, …) straight from Minn via wc/v3, no longer read-only.
  • Media editing: The media overlay is larger and lets you edit an image's title and alt text in place instead of bouncing to wp-admin.
  • Content bulk actions: Select rows in Content to bulk-change status or move to trash. Shift-click a checkbox to select a whole range; Esc clears the selection.
  • Redirect editing: The Redirects (Redirection) detail modal can now edit a redirect's source URL, target URL and HTTP status in place — via a small generic "editable fields" capability on the surface API that other adapters can opt into.
  • Permalink settings: The Settings → Permalinks stub is now real. Core leaves permalink_structure out of wp/v2/settings, so Minn exposes its own minn-admin/v1/permalinks endpoint (GET/POST, manage_options): structure presets or a custom structure with tag validation, category/tag bases, the same normalization as options-permalink.php (including the /index.php prefix when URL rewriting is unavailable), and an automatic rewrite flush. If a save flips the site between pretty and plain permalinks, the app reloads itself at its new home (/minn-admin/?minn_admin=1).

Improved

  • Toolbars stay put: Switching a user role (or a content category/tag filter) no longer blanks the whole view — the toolbar stays in place and only the table dims while the new data loads.
  • Scrolling tabs: Tab strips with many entries (all the user roles on a big site) now scroll horizontally on one line instead of wrapping and clipping.
  • Phone layout: A real mobile breakpoint. The topbar compacts to the essentials, toolbars wrap (tab strip on its own scrollable row, full-width search), the Content/Orders/Users tables drop secondary columns instead of clipping, plugin surface tables scroll sideways, the settings nav becomes a scrollable row, and the app height tracks mobile Safari's collapsing URL bar. Touch niceties: visible media prev/next arrows, larger checkboxes, and inputs sized so iOS doesn't zoom on focus.

Fixed

  • Resend sends to every recipient: Resend in the Email Log now extracts the full To list from the event record (scoped to the to collection, so cc/bcc addresses are never promoted into the To header). Previously it reused the truncated display string and silently dropped recipients beyond the first two.
  • Open raw shows source, not a live page: The Email Log's raw view opens the message as plain text. Opening it as HTML would have run any scripts in the logged email with the app's own origin.

v0.2.0 - July 3, 2026

The first expansion. Theme installs and management, plugin installs, redirect and activity log surfaces, notifications, featured images, and traffic on the Overview. The editor learns tables, verse, citations and syntax-highlighted code languages, and an About dialog explains what Minn is.

Added

  • Code block languages: A language picker (PHP, JS, HTML, CSS, bash, JSON, Python, SQL) appears in the editor toolbar whenever the caret is inside a code block. The choice is stored as a Prism-style language-* class on the <code> element — portable and theme-highlighter compatible — and drives language-aware syntax highlighting, including PHP $variables and <?php tags.
  • Dark code surfaces: Code blocks in the editor and previews always render on a dark surface with a fixed highlight palette, so syntax colors are equally readable in light and dark themes.
  • Theme installs: An "Add theme" flow on the Themes tab with a WordPress.org search picker (screenshot cards, install and activate in place) and zip upload via drag-and-drop or file picker.
  • Redirects: A bundled Redirection adapter lists redirects (source, target, status code, hits, last access) straight from its redirection/v1 API, with enable, disable and delete actions via its bulk endpoints.
  • Activity Log: A bundled Simple History adapter surfaces the audit log as a native Minn view — events with who/level/when columns, Warnings and Errors tabs, and detail modals — visibility following Simple History's own view capability.
  • Plugin installs: An "Add plugin" modal on Extensions with a WordPress.org search picker (server-side proxy — the app never talks to external hosts), install/activate in place, and zip upload via drag-and-drop or file picker.
  • AI Access: Your account now manages application passwords — create a revocable credential for an AI agent (shown once, with copy-password and copy-curl buttons) and revoke any credential — plus a generated agent guide: a markdown REST reference tailored to what's installed on the site (core routes, WooCommerce, Gravity Forms, ACF, Minn extras), ready to hand to a coding agent.
  • Notifications: Individual notifications mark read on click and navigate to the thing they're about (comments → moderation, updates → Extensions, new users → Users).
  • Featured images: A Featured image card in the editor sidebar with a thumbnail preview, set/replace via the media picker, and remove. Saves through the normal post save and autosave.
  • Tables, verse and citations in the editor: Tables are now editable inline (insert a 2×2 via the / menu, edit cells directly; hasFixedLayout round-trips), verse and preformatted blocks keep their block type on save instead of becoming code blocks, and quote citations (<cite>) are preserved.
  • Theme management: Extensions gains a Themes tab with screenshots, active/update badges, activate (with confirmation), per-theme update, and delete for inactive themes.
  • Traffic on the Overview: A new minn_admin_traffic filter lets analytics plugins power the Overview chart. When a provider is active, the Activity chart becomes a real Traffic chart (visitors per day/week with a source badge) and a Visitors stat card with a period-over-period delta leads the dashboard. Ships with adapters for Koko Analytics, WP Statistics, Burst Statistics and Independent Analytics, each reading the plugin's local tables directly; sites without an analytics plugin keep the Activity chart. Traffic bars stack pageviews behind visitors, and hovering any bar shows a Koko-style card with the date, visitors and pageviews (or event count on the Activity chart).
  • About Minn: A help icon in the topbar (and ⌘K entry) opens the philosophy page — what Minn is for, the AI-agent configuration model, and the no-lock-in guarantees — with links to the docs.

Fixed

  • Plugin names are cleaned of keyword-stuffed suffixes everywhere ("Rank Math SEO", not "Rank Math SEO – AI SEO Tools to Dominate SEO Rankings") and HTML entities are decoded in wp.org search results; full names remain available on hover.
  • Slash-menu inserts (table, divider, image) land at the top level of the document instead of nested inside the current block's wrapper, and wrapper divs created by contenteditable are serialized as their real child blocks instead of raw HTML.
  • Stat cards flow into a single row regardless of count, and activity entries with invalid modified dates are skipped.
  • Panels and modals no longer replay their entrance animation on every re-render — the notification panel opened with a double flash and flashed on tab switches, and the plugin-search modal flashed on each keystroke.
  • Line breaks inside code blocks (entered as <br> by the browser) are preserved when saving.
  • Classic-content saves now strip syntax-highlight decoration from code blocks before writing to the database.
  • Elementor's internal post types (templates, floating elements) no longer appear as Content tabs.

v0.1.0 - July 3, 2026

The first release. A standalone admin SPA at /minn-admin/ with Overview, Content, Media, Orders, Users, Comments, Extensions and Settings, a writing-first editor that preserves complex blocks byte-for-byte as islands, a command palette, plugin surfaces and editor panels for extensions, and a GitHub self-updater. Classic wp-admin stays fully available alongside.

Added

  • Minn Admin app: A reimagined WordPress admin served at /minn-admin/ — a standalone single-page app that talks to the WordPress REST API and lives alongside the classic wp-admin.
  • Overview: Real stat cards (posts, pages, comments, media storage), an activity chart with 7d/30d/90d ranges, and a recent-activity feed.
  • Content: Combined posts, pages and custom post types with status pills, author and modified columns, title search, and Load-more pagination.
  • Media: Grid and list library views with real thumbnails, an Upload button, and drag-and-drop uploads from anywhere in the app. Clicking a file opens a preview overlay (image/video/audio playback, metadata, copy URL, open, delete). Arrow keys and on-screen buttons step through the library inside the preview. The Upload button reveals a drag-and-drop zone with a file picker.
  • Orders: WooCommerce orders view (when WooCommerce is active) with monthly summary cards, status tabs, and an order detail overlay with line items.
  • Users: Searchable user directory with roles and registration dates, plus full user management — create users (with password generator), edit name/email/role, set new passwords, and delete with content reassignment. Each user's active login sessions are listed (browser, IP, sign-in time) with per-session sign-out and "Sign out everywhere".
  • Plugin surfaces: A declarative extension API (minn_admin_surfaces filter) that renders third-party plugin data with Minn's generic list/tabs/detail/action primitives — no JavaScript required from the integrating plugin. Ships with two bundled adapters: Gravity Forms (entries per form, field-label resolution, trash action) and Gravity SMTP (email log via a custom-table REST shim). See docs/for-plugin-authors.md.
  • Editor panels: A second extension class for per-post fields (minn_admin_editor_panels filter) rendered in the editor sidebar with native inputs and autosave. Ships with an ACF / ACF Pro adapter: field groups with "Show in REST API" appear as editable panels (text, textarea, number, select, radio, true/false…), with advanced field types deferring to wp-admin.
  • Clean URLs: Path-based routing (/minn-admin/content instead of #/content) with pretty permalinks, including deep links, back/forward support, and automatic migration of legacy hash links. Falls back to hash routing on plain permalinks.
  • Comments: Moderation view with Pending/Approved/Spam/Trash tabs and approve, spam, trash, restore and delete actions, plus a pending-count badge in the sidebar.
  • Extensions: Activate/deactivate plugins with a switch, update badges, and one-click "Update all". Inactive plugins can be deleted from the card. Plugins with updates get a per-plugin "Update → x.y" button.
  • Settings: General, Writing, Reading and Discussion sections backed by the core settings endpoint, plus a built-in maintenance mode. General includes a timezone picker, date/time formats and week start.
  • Editor: Distraction-free, block-aware writing surface. New posts save native Gutenberg block markup; complex blocks render as atomic read-only islands preserved byte-for-byte on save, so text stays editable around any layout; classic posts stay classic. Autosave, one-click publish, slash commands (type / for headings, quotes, code, lists, images, dividers), code blocks get dependency-free syntax highlighting, image insertion from the media library, editable categories, and post scheduling with a date/time picker. A Publish-panel link previews drafts or views published posts on the frontend, and a History card lists recent revisions with preview and one-click restore. Posts and pages can be moved to trash from the editor. See docs/editor-direction.md for the hybrid-editor rationale.
  • Command palette: ⌘K / Ctrl-K everywhere, with navigation and actions.
  • Notifications: Pending comments, plugin/core updates and new users with per-user unread tracking.
  • Themes: Dark and light, persisted per browser. Bundled variable fonts (Hanken Grotesk, JetBrains Mono) — no external font requests.
  • Self-updater: Update checks against the GitHub manifest with install from GitHub Releases.