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 throughminn_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 indocs/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 newminn_admin_traffic_dayfilter. The Visitors card now always names pageviews alongside the period delta. Documented indocs/for-plugin-authors.md. -
Status-card charts: a surface status payload may include a
chartseries (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 indocs/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
viewsarray 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 indocs/for-plugin-authors.mdand 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_formwith 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
settingscontract grows item scope: a route containing{id}renders per item instead of globally, entered from a row'ssettingsItemaction (the Settings tab leaves the view switcher, and the toolbar names the item). Documented indocs/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_settingsstore under theirgravitysmtp_*_routingcaps. 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_idso 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
.wpressexports 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_scriptsfor 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
fnwhile every other Minn context menu (andopenMinnMenuitself) usesrun, so clicking Deactivate or Re-verify closed the menu and did nothing. The license menu now usesrun, and the menu helper also accepts a legacyfnalias 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_Upgraderruns. 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 redundantwp_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>frominsertHTMLinto a styled span), so ⌘Z could not restore the backticks. The wrap now ridesinsertHTMLwith 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'shrefdocumented{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.