1293 lines
75 KiB
Markdown
1293 lines
75 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to Aurora Admin are documented here, one entry per
|
||
version bump. Starts at 2.1.0 — earlier history (the theming rebuild,
|
||
window chrome/taskbar, Site Editor support, etc.) lives in `git log` and
|
||
`PROJECT_STATUS.md`, not reconstructed here.
|
||
|
||
## [3.6.1] - 2026-07-11
|
||
|
||
### Fixed
|
||
- **Second round of misplaced `phpcs:ignore` fixes**, found via another fresh Plugin Check report after 3.5.1's fix. Turns out `WordPress.DB.DirectDatabaseQuery.DirectQuery`/`NoCaching` and `WordPress.DB.PreparedSQL.NotPrepared`/`InterpolatedNotPrepared` are attributed by PHPCS to *different* lines within the same multi-line `$wpdb->get_results()`/`get_row()` call — `DirectQuery`/`NoCaching` to the outer call's opening line, `NotPrepared` to whichever inner line the interpolated table name physically appears on. 3.5.1's fix moved every ignore comment down to cover the inner line (fixing `NotPrepared`) but broke coverage of the outer line (`DirectQuery`/`NoCaching` came back) for four calls in `MenuCreatorData.php` and `Notices.php`/`NoticesData.php` that hadn't already been collapsed to a single line. Fixed by collapsing those four remaining multi-line calls too — consistent with the single-line-call pattern used everywhere else in the 3.5.1 fix, which a single ignore comment reliably covers regardless of which sniff PHPCS attributes to that line. Re-verified with the automated scan plus live REST-dispatch functional round-trips.
|
||
|
||
## [3.6.0] - 2026-07-11
|
||
|
||
### Changed
|
||
- **Site Backup extracted into a standalone companion plugin,** at the
|
||
user's explicit request, following the same pattern as File Manager
|
||
(3.4.0) and Database Explorer (3.5.0) — proactive risk reduction, not a
|
||
WP.org rejection: restoring a backup means writing arbitrary files back
|
||
into the site, the same class of thing that's kept file-management
|
||
functionality out of Aurora Admin proper.
|
||
- The entire `admin/src/Backup/` tree (job/schedule storage, DB dumper,
|
||
file archiver, the state-machine engine, wp_cron safety net, and all
|
||
four storage providers — local, S3-compatible, Google Drive, plus the
|
||
provider interface/factory) and all four Backup REST controllers
|
||
moved, unmodified in behavior, into a brand-new sibling plugin:
|
||
**Aurora Site Backup** (`aurora-site-backup.php`, own bootstrap, own
|
||
REST namespace `aurora-site-backup/v1`, own Vite build). Since this
|
||
plugin needs its own settings storage independent of Aurora Admin
|
||
(S3 credentials, Google Drive OAuth tokens), a small standalone
|
||
`Options\Settings` class was added, backed by its own
|
||
`aurora_site_backup_settings` option — same minimal shape as Aurora
|
||
Admin's own Settings class, just a separate store.
|
||
- `CompanionPluginData.php`'s `PLUGINS` config array (already
|
||
generalized in 3.5.0) gained a `site-backup` entry — no new PHP
|
||
needed beyond the config line. The Settings → Add-ons screen now
|
||
lists all three companion plugins.
|
||
- Verified live via a full `rest_do_request()` dispatch: created a real
|
||
backup job, stepped it through the DB-dump phase, and canceled it —
|
||
end-to-end confirmation the extracted code still works, not just that
|
||
it loads without fatals.
|
||
- **Deployment gap, same as the other two companion plugins**: the
|
||
`aurora-site-backup.zip` is not yet hosted at
|
||
`https://aurora.auroradragon.studio/aurora-site-backup.zip` — the
|
||
Add-ons "Install & Activate" button for it will fail with a fetch
|
||
error until that's deployed (needs explicit go-ahead).
|
||
|
||
## [3.5.1] - 2026-07-11
|
||
|
||
### Fixed
|
||
- **Misplaced `phpcs:ignore` comments from the 3.3.2 compliance pass, found via a fresh Plugin Check report.** WPCS's `phpcs:ignore` suppresses violations reported on the exact next physical line — but several annotations added in 3.3.2 sat above the *opening* line of a multi-line `$wpdb->get_results()`/`get_row()`/`get_var()` call (e.g. `$rows = $wpdb->get_results(`), while PHPCS actually attributes the violation to whichever line further down inside that call contains the interpolated table-name/column tokens. Those suppressions were silently never taking effect. Fixed across `MenuCreatorData.php`, `NoticesData.php`, `Notices.php`, `BackupSchedules.php`, `BackupJobs.php`, `MediaFolders.php` (the largest cluster — collapsed most multi-line query calls to a single physical line so one ignore comment reliably covers every sniff PHPCS reports on that line, added a `MediaFolders::name_taken()` helper to replace an inline `while()` condition that couldn't otherwise be annotated), `DbDumper.php`, `AnalyticsData.php`, and `MediaData.php`'s `post__not_in` VIP-advisory comment. Also added a genuinely missing annotation on `Analytics::record()`'s `$wpdb->insert()` call. Verified with an automated scan confirming every `$wpdb->` call with dynamic table/query construction is now immediately preceded by its ignore comment.
|
||
- **Real bug found during verification, unrelated to Plugin Check**: `MenuCreatorData::create()` built its internal follow-up "fetch the row I just inserted" request as `new \WP_REST_Request("GET", "", ["id" => $wpdb->insert_id])` — but `WP_REST_Request`'s third constructor argument doesn't populate what `get_param()` reads, so `get_one()` always received a null id and returned "Menu not found" instead of the newly created menu. Confirmed via a full `rest_do_request()` dispatch (not just a direct function call) that this reproduced through the real REST route. Fixed by building the request with `set_url_params()`, WP core's own documented pattern for this.
|
||
- Confirmed the `compressed_files`/`hidden_files`/`unexpected_markdown_file` findings in the Plugin Check report (build zips, `.gitignore`, `.claude/`, `PROJECT_STATUS.md`) are scanner noise from scanning the whole development repository, not the actual submission zip — verified via `unzip -l` that none of those paths exist in `wporg-submission/aurora-admin.zip`.
|
||
|
||
## [3.5.0] - 2026-07-11
|
||
|
||
### Changed
|
||
- **Database Explorer extracted into a standalone companion plugin,** for
|
||
the same reason and following the exact same pattern as File Manager
|
||
in 3.4.0: direct database-query tooling (browsing tables, running
|
||
free-form SELECT/SHOW/DESCRIBE/EXPLAIN queries from wp-admin) is
|
||
treated by WordPress.org's Plugin Directory review the same way as
|
||
file-management functionality — outside what it accepts in a
|
||
directory-listed plugin. Rather than wait for a rejection to confirm
|
||
it or delete the feature outright:
|
||
- `admin/src/DatabaseExplorer/DatabaseExplorerData.php` and its Vue
|
||
UI (plus the shared `AppListShell`/`AppListItem` list-detail layout
|
||
it's built on) moved, unmodified in behavior, into a brand-new
|
||
sibling plugin: **Aurora Database Explorer**
|
||
(`aurora-database-explorer.php`, own bootstrap, own REST namespace
|
||
`aurora-database-explorer/v1`, own Vite build). Works completely
|
||
standalone, verified live via direct HTTP request with a
|
||
server-generated auth cookie — the admin page renders its mount
|
||
div and enqueued script correctly, and the REST namespace is
|
||
registered and reachable.
|
||
- `CompanionPluginData.php` was generalized from a single
|
||
file-manager-only class into a small `PLUGINS` config array keyed
|
||
by slug, so both File Manager and Database Explorer (and any future
|
||
companion plugin) share the same install/activate/status REST
|
||
routes and `Plugin_Upgrader`-based installer logic — adding a new
|
||
companion plugin going forward is a config entry, not new PHP.
|
||
- The **Settings → Add-ons** screen now lists both companion plugins.
|
||
- **Deployment gap, same as File Manager**: the Database Explorer zip
|
||
is not yet hosted at
|
||
`https://aurora.auroradragon.studio/aurora-database-explorer.zip` —
|
||
the Add-ons "Install & Activate" button for it will fail with a
|
||
fetch error until that's deployed (needs explicit go-ahead, same as
|
||
any other production deploy).
|
||
|
||
## [3.4.0] - 2026-07-11
|
||
|
||
### Changed
|
||
- **File Manager extracted into a standalone companion plugin.** WordPress.org's
|
||
second review response was unambiguous: the entire category of
|
||
file-management/code-editing functionality isn't accepted into the
|
||
Plugin Directory, regardless of the restrictions added in v3.2.1 —
|
||
the feature had to come out of Aurora Admin entirely for the
|
||
submission to be reconsidered. Rather than delete the functionality:
|
||
- `admin/src/FileManager/FileManagerData.php` and its three Vue
|
||
components moved, unmodified in behavior, into a brand-new sibling
|
||
plugin: **Aurora File Manager** (`aurora-file-manager.php`, own
|
||
bootstrap, own REST namespace `aurora-file-manager/v1`, own Vite
|
||
build). It works completely standalone — verified live with Aurora
|
||
Admin fully deactivated.
|
||
- The Theme Editor → File Manager redirect (`AppearancePages.php`) is
|
||
gone; visits to `theme-editor.php` now fall through to WordPress
|
||
core's own Theme Editor unmodified, which already respects
|
||
`DISALLOW_FILE_EDIT` itself.
|
||
- A new **Settings → Add-ons** screen offers one-click installation of
|
||
Aurora File Manager, wrapping `Plugin_Upgrader::install()` — the
|
||
same core API the native Plugins → Add New "Install Now" button
|
||
uses — pointed at a fixed, non-client-supplied HTTPS zip URL. No
|
||
settings/data are shared between the two plugins; Aurora Admin has
|
||
zero remaining code that touches the filesystem beyond its own
|
||
Site Backup archives.
|
||
|
||
## [3.3.2] - 2026-07-11
|
||
|
||
### Fixed
|
||
- **WordPress.org Plugin Check compliance pass** — a full re-run of the
|
||
official Plugin Check tool against the whole codebase (279 findings
|
||
across 26 files) surfaced several real gaps beyond the earlier v3.0.1/
|
||
v3.0.2/v3.2.1 passes, all now fixed:
|
||
- `readme.txt`'s `Stable tag` had drifted to 3.2.1 while the plugin
|
||
itself moved through 3.3.0/3.3.1 — a real mismatch that can prevent
|
||
WordPress.org from serving the correct download to users. Now kept
|
||
in lockstep with every version bump.
|
||
- `Analytics::country()` read `$_SERVER[$h]` directly for an
|
||
`empty()`/`strlen()` check before the existing sanitized copy was
|
||
computed — fixed by sanitizing once up front and using that
|
||
everywhere, rather than touching the raw superglobal at all.
|
||
- `AuroraAdmin.php`'s `defined("ABSPATH") || exit()` guard sat after
|
||
49 `use` import statements — functionally fine, but far enough into
|
||
the file that at least one automated file-access-protection scanner
|
||
didn't detect it. Moved to immediately after the `namespace`
|
||
declaration, this file's one deliberate departure from the rest of
|
||
the codebase's "guard after imports" convention.
|
||
- Roughly 230 `WordPress.DB.DirectDatabaseQuery`/`PreparedSQL`/
|
||
`UnescapedDBParameter` findings across every custom-table feature
|
||
(Site Backup, Media Folders, Activity Log, Analytics, Menu Creator,
|
||
Notices, Database Explorer) — verified each one is safe (internal
|
||
`$wpdb->prefix`-based table names or already-validated/escaped
|
||
identifiers, never raw user input) and annotated with the justified
|
||
`phpcs:ignore` the review process expects, matching the standard
|
||
already established for Database Explorer's query runner.
|
||
- A handful of `fread()`/`fwrite()`/`fclose()` calls adjacent to an
|
||
already-annotated `fopen()` were still individually flagged — WPCS
|
||
suppression is strictly per-line, so each sibling call in Site
|
||
Backup's file/S3/Google Drive streaming code now has its own
|
||
annotation too.
|
||
- Several `RuntimeException` messages interpolating internal (never
|
||
user-supplied) values were flagged as unescaped output — annotated
|
||
as exception messages, not HTML/browser output, the same
|
||
false-positive class WPCS is known to flag on exception
|
||
constructors.
|
||
|
||
## [3.3.1] - 2026-07-11
|
||
|
||
### Fixed
|
||
- **Settings page: nav and content now scroll independently.** Previously
|
||
the left category list and the right content panel scrolled together
|
||
as one long page — scrolling down the nav to reach a category near the
|
||
bottom (e.g. "Modern Image Formats") and clicking it left the content
|
||
panel's top scrolled out of view above the fold, requiring an extra
|
||
scroll back up to actually see it. Both panels now have their own
|
||
fixed-height scroll region, and switching categories resets the
|
||
content panel's scroll position to the top regardless of the nav's own
|
||
scroll position.
|
||
|
||
## [3.3.0] - 2026-07-11
|
||
|
||
### Added
|
||
- **Modern Image Formats** — a new Settings section that automatically
|
||
generates a WebP or AVIF sibling for every size WordPress produces from
|
||
a newly uploaded JPEG/PNG, and (optionally) rewrites `<img>` markup
|
||
into a `<picture>` element offering the modern format with the original
|
||
as a fallback source. "Automatic" output format prefers AVIF, falling
|
||
back to WebP, based on what the server's image editor actually
|
||
supports (`wp_image_editor_supports()`) — gracefully generates nothing
|
||
on a host that supports neither, rather than erroring. Purely additive:
|
||
original JPEG/PNG files are always kept, nothing about the attachment's
|
||
own metadata or file is changed, and generated files are cleaned up
|
||
automatically when the attachment is deleted. Only affects new
|
||
uploads — existing library images need a regenerate-thumbnails-style
|
||
tool to pick up the feature.
|
||
- Built entirely on documented WordPress core hooks
|
||
(`wp_generate_attachment_metadata`, `delete_attachment`,
|
||
`wp_editor_set_quality`, `wp_content_img_tag`,
|
||
`wp_get_attachment_image_html`) and `WP_Image_Editor::save()`'s
|
||
documented mime-type-conversion parameter — no third-party plugin
|
||
code, no Composer dependency.
|
||
- Verified live end-to-end: uploaded a real JPEG, confirmed a smaller
|
||
AVIF sibling was generated and recorded in attachment metadata,
|
||
confirmed a post embedding the image rendered a correct
|
||
`<picture><source type="image/avif" srcset="...">` wrapper, and
|
||
confirmed both the original and generated files were removed with no
|
||
orphans left behind after deleting the attachment.
|
||
|
||
## [3.2.1] - 2026-07-11
|
||
|
||
### Changed
|
||
- **File Manager: PHP/executable editing removed.** Rejected from the
|
||
WordPress.org Plugin Directory because File Manager let a
|
||
`manage_options` user open and overwrite *existing* `.php` files
|
||
in-place with immediate execution effect — no different in risk from
|
||
WordPress core's own Theme/Plugin editor, which core lets hosts disable
|
||
via `DISALLOW_FILE_EDIT` specifically because of that risk. File Manager
|
||
previously blocked creating/uploading/renaming-to executable file
|
||
types, but that same list wasn't enforced on *editing an existing* file
|
||
of that type — closed now: opening or saving any file matching
|
||
`BLOCKED_EXTENSIONS` (php, phtml, cgi, py, sh, and others) is refused.
|
||
File Manager also now honors `DISALLOW_FILE_EDIT` (blocks all editing)
|
||
and `DISALLOW_FILE_MODS` (blocks all create/upload/rename/delete/copy/
|
||
move/write operations), the same host-level lockdown constants
|
||
WordPress core's own file-modification flows already respect. Browsing,
|
||
downloading, and viewing file info are unaffected.
|
||
|
||
## [3.2.0] - 2026-07-11
|
||
|
||
### Added
|
||
- **Google Drive remote storage** for Site Backup — a second remote
|
||
storage option alongside S3-compatible, via OAuth 2.0. Each site
|
||
connects its own Google Cloud OAuth client (Client ID + Secret, pasted
|
||
into Settings) since a free, publicly-distributed plugin can't ship a
|
||
shared client secret; scope is the narrow `drive.file` (only
|
||
files/folders Aurora itself creates). Resumable upload and
|
||
`Range`-header chunked download against Drive API v3 mirror the
|
||
bounded-per-step design S3's multipart upload already established — no
|
||
changes to the job engine itself were needed, confirming the
|
||
storage-provider abstraction's original design goal. Shipped
|
||
code-complete and protocol-verified (request shapes checked against
|
||
Google's published API reference, and live-tested against Google's real
|
||
OAuth endpoints with placeholder credentials to confirm genuine API
|
||
errors come back); a full live "Connect" round-trip is left for the
|
||
user to verify once they have a real Google Cloud OAuth client and
|
||
HTTPS on the target site.
|
||
|
||
## [3.1.0] - 2026-07-11
|
||
|
||
### Added
|
||
- **Site Backup** — a new free sub-app: full site backup (database +
|
||
wp-content) and restore-in-place, on-demand or on a recurring daily/
|
||
weekly/monthly schedule, storing archives locally or on any
|
||
S3-compatible remote (AWS S3, Backblaze B2, Cloudflare R2, DigitalOcean
|
||
Spaces — one implementation via a configurable endpoint, no vendor
|
||
SDK, SigV4 signing implemented directly and verified against AWS's own
|
||
published test vectors).
|
||
- Built on a new resumable job-processing engine (`BackupEngine` +
|
||
`BackupJobs`) — the first background-job infrastructure in this
|
||
codebase. Every backup/restore step is bounded (row/file/byte count
|
||
and a wall-clock budget) so a multi-GB site never risks a single
|
||
request's timeout or memory limit. Two trigger paths converge on the
|
||
same step function: foreground polling from the Vue UI (fast
|
||
feedback while a tab is open) and a `wp_cron` safety net
|
||
(`BackupCron`) that keeps a job moving with no browser involved —
|
||
closing the tab mid-backup, or a scheduled backup with nobody
|
||
watching, both still reach completion.
|
||
- Database export/import (`DbDumper`) — paginated dump with schema
|
||
captured per-table (`DROP TABLE IF EXISTS` + `CREATE TABLE`, so
|
||
restore is deterministic and re-runnable from scratch), chunked
|
||
restore via a byte-cursor into the dump file. Aurora's own
|
||
backup-tracking tables are excluded from what gets backed up — a real
|
||
bug caught during testing, where restoring a snapshot of those tables
|
||
was overwriting the very job row driving the restore mid-flight.
|
||
- File archiving (`FileArchiver`) — a manifest of every file under
|
||
`wp-content/` (excluding the backup storage directory itself and,
|
||
structurally, `wp-config.php`, which lives outside `wp-content/`
|
||
entirely), zipped/extracted in bounded batches via `ZipArchive`,
|
||
reopened and appended to across isolated requests. Every extracted
|
||
entry is containment-checked (zip-slip protection) before anything is
|
||
written — verified live with a deliberately crafted malicious archive
|
||
entry, confirmed rejected.
|
||
- Local storage hardening — `wp-content/uploads/aurora-backups/` gets
|
||
WordPress core's own `index.php`/`.htaccess` stub pair; the real
|
||
protection is that every archive read goes through a
|
||
`manage_options`-gated REST route streaming the file through PHP,
|
||
never a guessable direct URL.
|
||
- Recurring schedules with count-based retention — a scheduled backup
|
||
prunes older ones (both the job row and its stored archive, local or
|
||
remote) down to the schedule's configured retention count.
|
||
- v1 deliberately does not include cross-domain migration (Duplicator's
|
||
own headline feature — generating an `installer.php` for a totally
|
||
different host) or restoring from an arbitrary uploaded archive
|
||
(restore only ever sources from Aurora's own backup history) — both
|
||
are real scope/risk decisions, not oversights.
|
||
- Live-verified end-to-end on the dev site, including catching and fixing
|
||
two real bugs along the way: a job's `phase` column wasn't updated to
|
||
a clean terminal value on completion (stale "Archiving files…" label
|
||
after a backup had actually finished), and a data-corruption bug where
|
||
manually pre-escaping newlines before `$wpdb->_real_escape()` (which
|
||
already does this) caused restored text fields to contain literal
|
||
backslash-n characters instead of real line breaks.
|
||
|
||
## [3.0.2] - 2026-07-11
|
||
|
||
### Fixed
|
||
- Plugin header validation error from the WordPress.org submission checker:
|
||
`Plugin URI` and `Author URI` were both `https://auroradragon.studio`,
|
||
and WP.org requires them to be distinct (one identifies the plugin, the
|
||
other the author). `Plugin URI` now points to
|
||
`https://aurora.auroradragon.studio` (the plugin's own marketing site);
|
||
`Author URI` stays on the studio's root site.
|
||
|
||
## [3.0.1] - 2026-07-11
|
||
|
||
### Fixed
|
||
- **WordPress.org Plugin Check compliance pass.** Ran the official Plugin
|
||
Check tool ahead of submission and fixed every real issue it surfaced
|
||
(257 flagged items, several dozen real):
|
||
- `WidgetsData.php`: replaced the forbidden `wp_get_sidebars_widgets()`
|
||
(internal-only core function) with a local helper reading the
|
||
`sidebars_widgets` option directly.
|
||
- `FileManagerData.php`: converted every raw filesystem call
|
||
(`move_uploaded_file()`, `mkdir()`, `rename()`, `unlink()`, `rmdir()`,
|
||
`is_writable()`, `readfile()`) to the `WP_Filesystem` API, which works
|
||
across hosting setups that don't allow direct filesystem access.
|
||
`move_uploaded_file()`'s upload-tampering check is preserved via an
|
||
explicit `is_uploaded_file()` call before handing off to
|
||
`WP_Filesystem::move()`.
|
||
- `BugReportData.php`: `parse_url()` → `wp_parse_url()`.
|
||
- `SubApps.php`: fixed a translation-function rule violation (page
|
||
titles now wrapped in `__()` at definition instead of being passed as
|
||
a variable to `__()` at the call site) and added justified
|
||
nonce-check suppressions on two read-only routing checks.
|
||
- Fixed missing `wp_unslash()`/sanitization on a handful of superglobal
|
||
reads (`Analytics.php`, `Shell.php`, `AnalyticsData.php`) and added
|
||
missing translator comments for two placeholder strings.
|
||
- Annotated dynamic-table-name SQL queries across `MediaFolders.php`,
|
||
`AnalyticsData.php`, `DatabaseExplorerData.php`, `NoticesData.php`,
|
||
`MenuCreatorData.php`, and `ActivityLogData.php` with justified
|
||
`phpcs:ignore` comments — every flagged table name comes from an
|
||
internal `$wpdb->prefix`-based helper, never user input, and table
|
||
identifiers can't go through `$wpdb->prepare()`'s value placeholders
|
||
(WordPress core has no API for arbitrary custom tables).
|
||
- Removed the stale `Domain Path: /languages/` plugin header (pointed
|
||
at a folder that's never existed — see 2.x-era removal of the fake
|
||
"13 languages" marketing claim).
|
||
- All changes live-verified against the LocalWP install: File Manager's
|
||
full create/rename/delete cycle exercised directly against the REST
|
||
routes (folder create, file create, rename, soft-delete, empty
|
||
trash), Widgets' sidebar-read endpoint, Database Explorer's table
|
||
browsing, and Media Folders' filtered listing all confirmed working
|
||
with zero console/PHP errors.
|
||
|
||
## [3.0.0] - 2026-07-06
|
||
|
||
### Removed
|
||
- **The entire licensing/monetization system.** Aurora Admin is being given
|
||
away free on the WordPress.org plugin repository — every feature
|
||
previously gated behind a paid license (Role Editor, Activity Log,
|
||
Database Explorer, File Manager, Analytics, White Label, Full Admin
|
||
Takeover, Media Folders) is now simply available to everyone, no key
|
||
required.
|
||
- Deleted `admin/src/Licensing/` entirely (`License.php`, `Integrity.php`,
|
||
the file-tamper-detection system that only existed to protect license
|
||
gating from bypass) and `bin/build-integrity-manifest.php`.
|
||
- Deleted the "Pro feature" upgrade-prompt UI (`UpgradeNotice.vue`,
|
||
`locked-feature.js`) and every lock badge in the sidebar.
|
||
- Removed the License key field and the dev-only "Simulate active
|
||
license" toggle from Settings — there's nothing left to license or
|
||
simulate.
|
||
- `license_key` and `dev_license_override` are actively purged from any
|
||
site's stored settings on upgrade (same cleanup pattern used for the
|
||
earlier Remote Site Switcher removal), not just hidden from the UI.
|
||
- Report a Bug still works, now via a direct call to the feedback
|
||
endpoint instead of going through the license-status layer.
|
||
- This is a clean split from the commercial `auroraplugins.com` service
|
||
(beta licenses, Pro purchases) — that server-side system is untouched
|
||
and unaffected by this change, it's simply no longer wired into this
|
||
codebase.
|
||
|
||
## [2.27.0] - 2026-07-06
|
||
|
||
### Added
|
||
- Restored the dev-only license override (`AURORA_ADMIN_DEV_MODE` wp-config.php
|
||
constant + Settings > Developer > "Simulate active license" toggle),
|
||
reversing the 2.25.0 removal. Requested explicitly for local testing on
|
||
admin.local — lets Pro features be exercised without a real license key.
|
||
**This must be stripped again before the next release/beta build** — same
|
||
standing rule as before, now re-documented in `PROJECT_STATUS.md`. Only
|
||
has any effect when `AURORA_ADMIN_DEV_MODE` is defined truthy in a given
|
||
install's own `wp-config.php`, never set in the repo or any built zip.
|
||
|
||
## [2.26.0] - 2026-07-05
|
||
|
||
### Added
|
||
- "Report a Bug" page (Aurora sidebar section), a real WordPress admin page
|
||
(`aurora-admin-bug-report`, registered via `SubApps.php` like Menu
|
||
Creator/Admin Notices) with a single free-text field plus auto-filled,
|
||
read-only diagnostics (plugin version, WordPress version, PHP version,
|
||
active theme, last 4 characters of the license key — not the full key).
|
||
Submits to a new `POST aurora-admin/v1/bug-report` REST route
|
||
(`admin/src/Rest/BugReportData.php`), which forwards to a new
|
||
`License::submit_bug_report()` method that calls the license server.
|
||
- **License server** (`aurora-licensing` plugin, not this repo): added a
|
||
`wp_aurora_bug_reports` table (DB version 3 → 4, same version-gated
|
||
migration idiom) and a new public `POST /report-bug` REST route,
|
||
storing the description plus whatever license key/domain/diagnostics
|
||
fields were sent. Deliberately a plain `wpdb->insert` with no admin UI
|
||
yet — reports are reviewable via `wp db query` for now; a dashboard can
|
||
come later if report volume justifies it.
|
||
- Verified live end-to-end (not mocked): submitted a real report through
|
||
the actual Report a Bug page, confirmed it landed correctly in
|
||
`wp_aurora_bug_reports` on the production server, then deleted the two
|
||
test rows (one from an earlier curl smoke test) by exact ID.
|
||
|
||
## [2.25.0] - 2026-07-05
|
||
|
||
### Removed
|
||
- Dev-mode license override (`AURORA_ADMIN_DEV_MODE` wp-config.php constant,
|
||
Settings > Developer category's toggle, and every call-site in
|
||
`License::is_active()`/`is_feature_available()`) — this was a
|
||
build-time-only escape hatch for testing paid features without a live
|
||
license, marked in `PROJECT_STATUS.md` as "MUST BE REMOVED BEFORE A
|
||
RELEASE BUILD" since it shipped in the plugin zip. Real beta testers are
|
||
about to install real builds, so it had to go before that zip goes out.
|
||
Paid features now gate purely on `License::is_active()` for everyone,
|
||
no exceptions.
|
||
|
||
## [2.24.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Beta tester license support, end to end. User asked for 10 new 30-day
|
||
beta licenses plus a way to flag/display beta status in the plugin.
|
||
- **License server** (`aurora-licensing` plugin on the live
|
||
`auroraplugins.com` box, not this repo): added an `is_beta` column to
|
||
`wp_aurora_licenses` (migrated in place via a `plugins_loaded`-hooked
|
||
check, since the file was updated without re-activation — same
|
||
version-gated migration idiom this plugin's own `ActivityLog.php`
|
||
etc. use), a `wp aurora-lic generate-beta <count> [--days=<n>]
|
||
[--max-sites=<n>]` WP-CLI command (not a public REST route —
|
||
generating free licenses has to stay admin/shell-only), and `is_beta`
|
||
added to `/validate` and `/activate`'s response payloads. Generated
|
||
the 10 requested keys (30-day expiry, 1 site each) — see the
|
||
conversation for the actual key list; not duplicated here since this
|
||
file ships to customers.
|
||
- **Client** (this plugin): `License::is_beta_tester()` reads the
|
||
server's `is_beta` flag (already flowing through the existing
|
||
`status()` cache — no new caching logic needed). Settings > General's
|
||
license status line now shows "Beta Tester license active — expires
|
||
in N days (date)" instead of the normal "License active (plan)" text
|
||
when a beta key is active. A beta license is a real, fully-functional
|
||
`is_active()` license like any other — this is a display flag only,
|
||
not a separate gating path.
|
||
- Verified against the real production license server, not a mock:
|
||
generated a real key via the new CLI command, activated it from the
|
||
dev site's actual Settings page, confirmed the badge and expiry
|
||
countdown render correctly, then cleared the key (deactivating it
|
||
server-side via the existing `on_settings_updated` flow).
|
||
|
||
## [2.23.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Full field-set parity for Writing/Reading/Discussion native Settings
|
||
screens, closing the gap flagged in 2.22.0's audit.
|
||
- **Writing**: `Default Post Category` and `Default Post Format` are now
|
||
real dropdowns (populated from `get_categories()`/
|
||
`get_post_format_strings()`) instead of raw numeric IDs. Added
|
||
`use_smilies` — registered in core's own REST settings schema but
|
||
never actually added to this screen.
|
||
- **Reading**: `Homepage`/`Posts Page` are now page-title dropdowns
|
||
(via `get_pages()`) instead of raw page IDs, and only appear once
|
||
"Homepage Displays" is set to "A static page" — matching native
|
||
WordPress's own conditional reveal. New generic `showIf` field
|
||
property in `NativeSettings.vue` (`{key, equals}`) drives this,
|
||
reusable by any future field.
|
||
- **Discussion**: went from 2 fields to full native parity (~24 fields:
|
||
pingback/comment defaults, moderation rules, threaded-comment
|
||
settings, pagination, three notification-email toggles, comment
|
||
moderation/disallowed-keys blocklists, and avatar settings). Core's
|
||
REST settings schema (`register_initial_settings()`) only ever
|
||
exposed 2 of Discussion's real options — everything else needed a new
|
||
dedicated controller, `DiscussionData.php`, doing raw `get_option()`/
|
||
`update_option()` reads/writes against an explicit key allowlist (same
|
||
pattern as `PermalinksData.php`, generalized to many keys instead of
|
||
one).
|
||
- New `textarea` field type in `SettingsField.vue` for the two
|
||
moderation-keys blocklist fields (multi-line plain text — nothing
|
||
else on any settings screen needed one until now).
|
||
- Verified live: dropdowns populate with real data, conditional fields
|
||
show/hide correctly, and a real save-then-reload round trip on
|
||
Discussion (toggled a setting off, saved, reloaded fresh, confirmed
|
||
the change persisted) — not just an optimistic-UI check.
|
||
|
||
## [2.22.0] - 2026-07-05
|
||
|
||
Full plugin audit, requested after the plugin-delete crash raised the
|
||
question of what else might be broken or incomplete. Checked every
|
||
sidebar screen live (console + PHP error log at each stop), re-verified
|
||
the license-activation claim from last session against the actual code,
|
||
and closed the one remaining documented security gap.
|
||
|
||
### Fixed
|
||
- **REST-bypass gap closed for Role Editor, Activity Log, and Database
|
||
Explorer** — their REST controllers only checked
|
||
`current_user_can('manage_options')`, not the license, so a direct REST
|
||
call could reach paid functionality (including Database Explorer's raw
|
||
SQL runner) with no license at all. Same fix already applied to File
|
||
Manager/Media Folders earlier this session, just never circled back for
|
||
these three. Verified every other paid-feature REST controller (Themes,
|
||
Nav Menus, Widgets, Permalinks, Analytics, White Label) already had the
|
||
check — this was the last of them.
|
||
- **Permalinks screen was missing the standard structure presets** (Plain,
|
||
Day and name, Month and name, Numeric, Post name) — only the raw
|
||
"Custom Structure" text field existed, which is the one part of that
|
||
screen almost nobody actually uses by hand. Added the five presets as
|
||
radio options with live example URLs, auto-detecting which preset (or
|
||
"Custom") matches the currently-saved structure.
|
||
|
||
### Verified (no changes needed)
|
||
- Clicked through Dashboard, Posts, Pages, Media, Users, Comments,
|
||
Plugins, all Aurora sub-apps (Menu Creator, Admin Notices, Role Editor,
|
||
Activity Log, Database Explorer, File Manager), Media Upload, Add New
|
||
User, Profile, all 5 native Settings screens, and several Aurora
|
||
Settings categories (General, White Label, Analytics) — no fatals, no
|
||
new console errors anywhere in the pass.
|
||
- Confirmed License.php's activation/validation flow is real (calls
|
||
`auroraplugins.com`'s REST API, caches with TTL, tamper-checks) —
|
||
corrected a stale "still a placeholder" claim from earlier this session
|
||
and removed the outdated doc line that caused it.
|
||
|
||
### Known gaps (not fixed — flagged for a decision, not silently patched)
|
||
- Writing/Reading/Discussion native Settings screens expose only a
|
||
handful of fields each, several as raw text/numeric-ID inputs where
|
||
native WordPress has dropdowns (post category, post format, homepage
|
||
page picker) — functional but poor UX, and Discussion in particular is
|
||
missing most of its native moderation options. Larger effort than the
|
||
Permalinks fix; needs new endpoints (categories list, post formats) and
|
||
new field types, not just a values tweak.
|
||
- Comments list's pagination footer shows "0 to 0 of 0" despite the "All"
|
||
tab correctly showing a count — cosmetic, not investigated further.
|
||
|
||
## [2.21.2] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Deleting a plugin from Aurora's Plugins page ("major issue" per user
|
||
report) fataled the whole site with WordPress's generic "There has been
|
||
a critical error" page instead of actually deleting anything. Root
|
||
cause, found in the PHP error log: `PluginsData::delete_plugin()` called
|
||
core's `delete_plugins()`, which internally calls
|
||
`request_filesystem_credentials()` (WP_Filesystem setup) — that function
|
||
lives in `wp-admin/includes/file.php`, which a REST API request doesn't
|
||
load the way a normal wp-admin page load does, and `delete_plugin()`
|
||
only required `plugin.php`. `update_plugin()` right below it already
|
||
required `file.php` for the same underlying reason; `delete_plugin()`
|
||
just never got the same fix. Verified live: deleted a real plugin
|
||
(WP File Manager) end to end with no fatal, "Plugin deleted." message
|
||
shown correctly, confirmed no new error logged.
|
||
|
||
## [2.21.1] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Sidebar section accordion closed the wrong section on "hidden child"
|
||
native screens (theme-install.php, media-new.php, user-new.php, ...).
|
||
User: expand Appearance, click "Add New Theme", and the Appearance
|
||
section collapsed while the "AURORA" section at the bottom opened
|
||
instead — this was a different bug than the overlay-covers-the-sidebar
|
||
issue fixed in 2.21.0, this was specifically about which section stays
|
||
expanded. Root cause: `Sidebar.vue`'s accordion decides the open section
|
||
by matching the current URL against each menu item's own submenu array
|
||
(`MenuSerializer::serialize()`, scraped from WP's `$submenu` global) —
|
||
but these screens are deliberately absent from `$submenu` (WP's own
|
||
native left menu doesn't list "Add New Theme" as a link either, only
|
||
"Themes"/"Customize"/"Editor"), so no section ever matched and the
|
||
accordion fell through to its Aurora-expanded default.
|
||
- WP core itself solves this exact problem for its own native menu
|
||
highlighting via a `$parent_file` global, set directly in each of
|
||
these pages' own PHP (`theme-install.php` sets
|
||
`$parent_file = 'themes.php'`, `media-new.php` sets `'upload.php'`,
|
||
`user-new.php` sets `'users.php'`) — reused that instead of
|
||
hardcoding a list of "hidden child screen" mappings ourselves.
|
||
`Shell::print_mount()` now reads it and passes it through as
|
||
`activeParentFile`; `Sidebar.vue`'s `isSectionActive()` treats a menu
|
||
item as active when its id matches, alongside the existing exact-URL
|
||
checks. General fix — covers any current or future WP core (or
|
||
third-party plugin) screen using this same convention, not just the
|
||
three confirmed here.
|
||
|
||
## [2.21.0] - 2026-07-05
|
||
|
||
### Changed
|
||
- The theme-install.php "Preview & Install" overlay (clicking a theme card
|
||
under Appearance > Themes > Add New Theme) is now framed like the block
|
||
editor window instead of covering Aurora's sidebar/toolbar entirely.
|
||
User reported "it closes the menu" — confirmed this is WP core's own
|
||
native behavior (the fullscreen overlay covers the native admin menu
|
||
too, on a totally vanilla install), not a regression, but agreed a
|
||
framed treatment was worth the risk for visual consistency with how the
|
||
block editor is already handled.
|
||
- `.wp-full-overlay` (WP core's overlay component, shared with the
|
||
Customizer — only `.theme-install-overlay` specifically is touched,
|
||
not `.wp-full-overlay` generally) is reframed to Aurora's standard
|
||
inset box: the overlay itself plus its two independently
|
||
`position: fixed` children (`.wp-full-overlay-sidebar`,
|
||
`.wp-full-overlay-main`) each need the same left/top/bottom math
|
||
applied directly, since fixed descendants don't inherit an ancestor's
|
||
padding-box positioning the way absolutely-positioned ones do.
|
||
`margin-left` on `.expanded`/`.collapsed` mirrors WP core's own three
|
||
responsive breakpoints with Aurora's frame offset added on top, so the
|
||
sidebar collapse/expand slide animation keeps working unmodified.
|
||
- Root-caused and fixed two real bugs found while building this: (1)
|
||
opening the overlay adds `body.full-overlay-active`, and WP core's own
|
||
CSS sets `body.full-overlay-active { visibility: hidden }` with only
|
||
the overlay itself set back to visible — Aurora's entire shell
|
||
inherited that hidden visibility too (nested in body), which is what
|
||
silently erased the sidebar/toolbar instead of just having them
|
||
covered. Fixed with one override re-enabling visibility for Aurora's
|
||
own root specifically. (2) The overlay's own `height: 100%` (WP core)
|
||
combined with our `top`+`bottom` insets was the exact same
|
||
over-constrained-box bug already known from the block editor's
|
||
`.interface-interface-skeleton` — same `height: auto !important` fix.
|
||
- The traffic-light winbar needed a permanently-running `MutationObserver`
|
||
rather than a one-shot check: the overlay doesn't exist in the initial
|
||
DOM (WP core creates it lazily on first click), and every subsequent
|
||
theme selection fully re-renders the overlay's contents, wiping out
|
||
anything inserted into it — confirmed live (bar present after the
|
||
first click, gone after picking a second theme) before switching to an
|
||
idempotent "ensure inserted" observer callback.
|
||
- Verified live end-to-end: opening via natural clicks (not just direct
|
||
URL navigation), switching between themes with the prev/next arrows
|
||
(triggers the content-destroying re-render), closing and confirming
|
||
the sidebar/toolbar return correctly, no console errors at any step.
|
||
|
||
## [2.20.2] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Appearance > Themes was missing two capabilities the native Themes
|
||
screen has: browsing/installing themes from the WordPress.org directory,
|
||
and uploading a theme zip. `AppearancePages.php`'s `load-themes.php`
|
||
hijack never passed a link to `theme-install.php` (only `customizeUrl`),
|
||
so there was no way to reach either from Aurora's Themes page.
|
||
`Themes.vue` gains an "Add New Theme" button (next to Customize) linking
|
||
to native `theme-install.php`, gated on `current_user_can('install_themes')`
|
||
— that native screen already has both the WordPress.org browser (Popular/
|
||
Latest/Block Themes/Favorites/Feature Filter tabs, search) and an
|
||
"Upload Theme" button built in, so neither needed rebuilding. Same
|
||
reuse-native-flow-for-add pattern already used for Plugins' `addUrl`
|
||
(`plugin-install.php`) and Media's `newMediaUrl` (`media-new.php`).
|
||
|
||
## [2.20.1] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Font Library (`font-library.php`) rendered with a jarring mix of Aurora's
|
||
dark frame around a completely white, near-unreadable content area (light
|
||
text on a white card). WP 6.5+ built this screen on `@wordpress/
|
||
components`' newer "boot-layout" primitives instead of classic postbox
|
||
markup, so `native-dark.css`'s existing postbox/card rules never matched
|
||
its DOM. Added targeted dark-theme coverage for the screen's stable,
|
||
hand-authored class names (`.boot-layout-container`, `.boot-layout__stage`,
|
||
`.admin-ui-page`, `.admin-ui-navigable-region`, `.admin-ui-page__header`,
|
||
`.font-library-page__tab-panel`, `.font-library__tabpanel-layout`,
|
||
`.font-library__footer`, `.font-library__fonts-list-item`,
|
||
`.font-library__font-card`) — deliberately not touching this screen's
|
||
Emotion-generated hash classes (e.g. `css-qi2azi`), which aren't stable
|
||
across WP builds.
|
||
- Regenerated `admin/src/Licensing/integrity-manifest.json` and rebuilt
|
||
`dist/aurora-admin-v2.zip` from a fresh staging copy — the protected
|
||
files' checksums (`Integrity::is_tampered()`'s manifest) had gone stale
|
||
after this session's edits to `aurora-admin.php`, `Shell.php`, and others.
|
||
Also excluded `.claude/` from the staged copy — the internal tooling
|
||
config had been getting bundled into the distributable zip.
|
||
|
||
## [2.20.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Media Folders (paid — `License::PAID_FEATURES["media-folders"]`): a
|
||
folder tree for the Media Library, duplicating the organizing capability
|
||
of the FileBird Pro plugin at the user's request, with its own
|
||
independent schema (`wp_aurora_media_folders` /
|
||
`wp_aurora_media_folder_items`, distinct from FileBird's own `wp_fbv*`
|
||
tables so both can coexist) rather than importing FileBird's data.
|
||
- New `MediaFolders.php` model (create/rename/delete/reparent, one folder
|
||
per attachment) + `MediaFolderData.php` REST routes
|
||
(`/media-folders`, `/media-folders/assign`), every route double-gated
|
||
(`current_user_can` + `License::is_feature_available`) per this
|
||
project's established REST-bypass-hardening pattern.
|
||
- `Media.vue` gains a folder sidebar (`MediaFolderTree.vue`): create,
|
||
rename, delete, right-click context menu, drag-and-drop reparenting,
|
||
and drag-and-drop (or a "Move to folder" fallback) to file media into
|
||
folders. "All Media" and "Uncategorized" are pinned pseudo-folders.
|
||
- The Media Library page itself stays free/ungated either way — only the
|
||
folder capability is paid. Unlicensed users keep today's flat grid
|
||
unchanged; the sidebar shows an inline `UpgradeNotice` instead of
|
||
disappearing or locking the whole page — a new gating shape for this
|
||
codebase (previously: whole sub-app free or whole sub-app paid).
|
||
|
||
### Fixed
|
||
- `Shell::is_own_page()` didn't recognize `ScreenHijack`-based pages
|
||
(Posts, Pages, Media, Users, Comments — they keep their native URL, no
|
||
`?page=aurora-admin` to key off), so it misclassified them as native
|
||
pages and loaded `native-dark.css`'s own-page exclusion incorrectly,
|
||
letting that stylesheet's generic `a` color rule leak into the real
|
||
Aurora UI. Invisible until now because no earlier hijacked page rendered
|
||
a link relying on accent/contrast coloring — Media Folders' new
|
||
"Enter a license key" CTA in the unlicensed sidebar was the first.
|
||
`ScreenHijack::register()` now flags `is_hijack_active()` the moment any
|
||
registered hijack activates for the current request, and
|
||
`is_own_page()` checks it.
|
||
|
||
## [2.19.0] - 2026-07-05
|
||
|
||
### Removed
|
||
- Remote Site Switcher: the Settings > General "Remote Sites" repeater and
|
||
"Remote Site Switcher Capability" field, and the toolbar dropdown they
|
||
fed. User asked what it did; investigation found it was inert scaffolding
|
||
— it collected and stored a remote site's URL/username/application
|
||
password, but nothing anywhere in the codebase ever used the credentials
|
||
(no REST calls, no proxying, no SSO). The toolbar "switcher" was just a
|
||
plain link opening the remote site's own `/wp-admin/` in a new tab. User's
|
||
call: "doesn't really do much for the software" — removed rather than
|
||
built out, since a real cross-site integration wasn't the ask.
|
||
- `License::PAID_FEATURES["remote-site-switcher"]` — the feature's paid gate,
|
||
now dead code since the feature itself is gone.
|
||
|
||
### Added
|
||
- `Settings::remove_retired_keys()` — actively deletes now-unused settings
|
||
keys from the database on `init`, rather than leaving them inertly
|
||
stored. Added specifically because `remote_sites` held a real secret
|
||
(WordPress application passwords); once the field stopped being read or
|
||
written, the safer move was to purge it, not just stop touching it.
|
||
|
||
## [2.18.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Role Editor: an info icon next to every capability checkbox, with a
|
||
hover tooltip explaining what it actually does — user asked directly,
|
||
pointing at `level_0`/`level_1` as an example of capabilities with no
|
||
explanation anywhere in the UI. New `capabilityDescriptions.js` covers
|
||
all ~55 WordPress core capabilities (`edit_posts`, `manage_options`,
|
||
`unfiltered_html`, etc.) plus the legacy `level_0`–`level_10` "user
|
||
level" system specifically — a pre-2.0 permissions scheme WordPress
|
||
still assigns to every default role purely for backward compatibility
|
||
with old themes/plugins that check `current_user_can('level_N')`
|
||
directly instead of a named capability; core itself hasn't checked a
|
||
level in years. Any capability not in the dictionary (e.g. one added by
|
||
another plugin) gets a generic "custom capability" fallback rather than
|
||
showing nothing. Verified live: hovering `level_0`'s info icon on the
|
||
Subscriber role shows the explanation described above.
|
||
|
||
## [2.17.2] - 2026-07-05
|
||
|
||
### Fixed
|
||
- `AppListShell.vue` (the shared master/detail layout used by Database
|
||
Explorer, Role Editor, Activity Log, Admin Notices, and Menu Creator):
|
||
the list pane and detail pane shared one page-level scroll instead of
|
||
scrolling independently. Selecting an item near the bottom of a long
|
||
list (e.g. Database Explorer's 40 tables) left the detail panel's
|
||
newly-loaded content rendered off-screen above the current scroll
|
||
position — looked like nothing happened until you scrolled all the way
|
||
back up. Root cause: the shell only set a `min-height` on the outer
|
||
flex container, so it just grew with content instead of giving each
|
||
pane a capped height + its own scrollbar. Fixed by giving the container
|
||
a real `height` and both panes `height: 100%; overflow-y: auto`, with a
|
||
separate mobile-breakpoint treatment (stacked panes get natural height
|
||
with their own `max-height` instead of squashing to 50/50). Verified
|
||
live: scrolled Database Explorer's table list to the bottom, selected
|
||
`wp_users`, confirmed its data appeared immediately without scrolling.
|
||
|
||
## [2.17.1] - 2026-07-05
|
||
|
||
### Fixed
|
||
- File Manager's right-click context menu never appeared for real users
|
||
(it worked in earlier automated testing, which turned out to be
|
||
triggering the bug's absence rather than confirming its fix). Root
|
||
cause: right-clicking — especially via a trackpad's two-finger tap or
|
||
Ctrl-click on macOS — can fire a trailing synthetic `click` event
|
||
immediately after `contextmenu` on the same target. The menu's
|
||
"click anywhere else closes it" listener was attached synchronously the
|
||
moment the menu opened, so that trailing click closed it in the same
|
||
tick it appeared — a real race condition, not a rendering bug. Fixed by
|
||
deferring the outside-click listener's registration by one tick
|
||
(`setTimeout(..., 0)`) so it only starts listening after the opening
|
||
event has fully finished. Verified by simulating the exact race
|
||
(`contextmenu` immediately followed by `click` on the same element,
|
||
same tick) and confirming the menu stays open; also confirmed a genuine
|
||
later click still closes it.
|
||
|
||
## [2.17.0] - 2026-07-05
|
||
|
||
### Added
|
||
- File Manager: **right-click context menu**, mirroring the toolbar exactly
|
||
(same functions, just a different trigger) so the two can't drift out of
|
||
sync. Right-clicking an item outside the current selection selects just
|
||
that item first (standard file-manager behavior); right-clicking within
|
||
an existing multi-selection leaves it intact so bulk actions still work
|
||
from the menu. Right-clicking empty space shows folder-level actions
|
||
(New Folder/File, Upload, Paste) instead. Closes on Escape or a click
|
||
anywhere else.
|
||
- File Manager: the plain `<textarea>` editor is now a real code editor
|
||
(CodeMirror 6 — `codemirror` + per-language packages for JS/TS, CSS,
|
||
HTML, JSON, PHP, Markdown, XML, SQL), with syntax highlighting, line
|
||
numbers, code folding, and active-line highlighting. Language is chosen
|
||
by file extension; unrecognized extensions fall back to plain text
|
||
rather than guessing wrong. Themed directly off Aurora's own CSS
|
||
variables (not a hardcoded palette) so it matches whatever theme preset
|
||
is active instead of looking like a foreign widget. Adds real bundle
|
||
weight (~250KB gzipped) — only loaded when the File Manager page itself
|
||
is opened, not part of the main admin bundle.
|
||
- Verified live: context menu appears correctly for both selection and
|
||
empty-space cases with the right actions enabled/disabled, Escape closes
|
||
it; PHP syntax highlighting confirmed rendering correctly on a real file
|
||
(index.php — comments, strings, keywords all colored, doc-block folding
|
||
visible).
|
||
|
||
## [2.16.0] - 2026-07-05
|
||
|
||
### Changed
|
||
- File Manager's actions consolidated into a single elFinder-style toolbar
|
||
(back/forward/up navigation history, new folder/file, upload,
|
||
copy/cut/paste, rename, trash, download/edit/info, list/grid view toggle,
|
||
fullscreen, search) matching the layout of the "WP File Manager" reference
|
||
plugin, replacing the previous split of header buttons + a per-row Actions
|
||
column. Selection is now click-to-select (checkbox) + toolbar action,
|
||
double-click to open a folder or editable file — the toolbar's buttons
|
||
enable/disable based on what's currently selected (e.g. Rename/Info only
|
||
with exactly one item selected, Download only for a single file).
|
||
- **Move/copy switched from a destination-picker modal to clipboard-style
|
||
copy/cut/paste** — select item(s), click Copy or Cut, navigate anywhere
|
||
(tree sidebar, breadcrumb, double-click into a folder), click Paste. A
|
||
copy clipboard survives repeated pastes; a cut clipboard clears itself
|
||
after the first successful paste. Same `/file-manager/bulk` endpoint
|
||
underneath, just a different frontend trigger.
|
||
- Added a **grid view** (thumbnails/icons in a card layout) as an
|
||
alternative to the list view, and a **fullscreen toggle** for the File
|
||
Manager panel itself.
|
||
- Verified live: copy → navigate into a folder → paste (file appeared in
|
||
the new location) → select → trash → confirmed removed; back-navigation
|
||
and grid view toggle both confirmed working.
|
||
|
||
## [2.15.0] - 2026-07-05
|
||
|
||
### Added
|
||
- File Manager closed most of the feature gap against the reference "WP
|
||
File Manager" plugin, adding everything that didn't carry the security
|
||
risk of the already-excluded zip/unzip and chmod features:
|
||
- **Move & copy** between folders (`copy_item`/`move_item`), with
|
||
same-containment checks as everything else plus a specific guard
|
||
against moving/copying a folder into its own descendant. Name
|
||
collisions at the destination get " (2)", " (3)", etc. appended rather
|
||
than silently overwriting.
|
||
- **Multi-select + bulk actions** — one `/file-manager/bulk` endpoint
|
||
drives trash/move/copy across any number of selected items, reusing
|
||
the exact same per-item logic as the single-item buttons so bulk
|
||
behavior can't drift from what those do. Partial failures don't abort
|
||
the rest — every path gets its own attempt, failures are reported back.
|
||
- **Trash instead of permanent delete** — deleting now moves the item
|
||
into a flat UUID-named folder under `wp-content/uploads/aurora-admin-trash/`
|
||
plus a JSON manifest (original path, name, type, deleted-at), rather
|
||
than encoding the original path into the filename (nesting/special
|
||
characters/length limits make that fragile). Trash view offers
|
||
restore (recreates parent folders as needed, blocks if something's
|
||
since taken the original spot), permanent delete, and empty-trash.
|
||
- **Folder tree sidebar** — lazy-loaded (only fetches a folder's children
|
||
when expanded) via the existing list endpoint filtered to directories,
|
||
no new backend route needed. Reused as the destination picker for
|
||
move/copy.
|
||
- **File info panel** — read-only permissions/owner/size/dates/mime type
|
||
via a new `/file-manager/info` endpoint; directory size is computed
|
||
on-demand for this one-off request rather than for every row in the
|
||
main list (would slow down browsing large folders for no benefit).
|
||
- **Image thumbnails** — a new `/file-manager/preview` endpoint serves
|
||
image files inline (not as an attachment) for use as an `<img>` src;
|
||
no server-side resizing, just the extension allowlist + size cap every
|
||
other endpoint here already uses.
|
||
- **Drag-and-drop upload** (multiple files at once) and **sortable
|
||
columns** (Name/Size/Modified, folders always first regardless of
|
||
sort) — both frontend-only, no new backend surface.
|
||
- Aurora's own trash folder is hidden from the normal browser view when
|
||
listing `wp-content/uploads` — it's an implementation detail, not a
|
||
real user-created folder.
|
||
- Verified live: multi-select, info panel, and the full create → trash →
|
||
restore round trip through the UI; copy/bulk-trash/empty-trash verified
|
||
directly against the REST endpoints.
|
||
- Still deliberately not built (unchanged from the original scope decision):
|
||
zip/unzip (zip-slip risk) and chmod/permissions editing (too easy to lock
|
||
yourself out).
|
||
|
||
## [2.14.0] - 2026-07-05
|
||
|
||
### Added
|
||
- **Developer-only** license override for local testing — lets Pro
|
||
features be tested without buying a license against the developer's own
|
||
software. Settings > Developer's "Simulate active license" toggle treats
|
||
every paid feature as fully licensed, bypassing both the real license
|
||
check and the file-integrity tamper check. Two gates keep this from ever
|
||
doing anything on a real install even if this code ships by accident:
|
||
(1) it only has any effect at all when `AURORA_ADMIN_DEV_MODE` is
|
||
defined truthy in `wp-config.php` — never set anywhere in this repo or
|
||
the release zip, only in a local dev environment's own config — and (2)
|
||
the Settings > Developer category itself only renders in the UI when
|
||
that constant is present. **This entire feature (the `DEV_MODE_CONSTANT`
|
||
checks in `License.php`, the `devModeAvailable` flag in
|
||
`SettingsPage.php`, and the "Developer" category in
|
||
`settingsConfig.js`/`Settings.vue`) must be removed before packaging a
|
||
release build** — every touch point is marked `DEV ONLY` in comments.
|
||
Verified live: toggling it on/off correctly unlocks/re-locks a Pro
|
||
feature (Role Editor) end-to-end, including the sidebar's lock badge.
|
||
|
||
## [2.13.1] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Every `ScreenHijack`-mounted page (Posts, Pages, Media, Users, Comments,
|
||
the 5 native Settings screens, Media Upload, Add New User, Nav Menus,
|
||
Themes, Widgets, Profile) was missing the traffic-light title bar and
|
||
rendering outside the normal card frame — the DOM structure didn't match
|
||
native/other Aurora pages. Root cause: WordPress prints
|
||
`<div id="wpbody"><div id="wpbody-content">` *after* the
|
||
`in_admin_header` hook fires (confirmed directly in core's
|
||
`admin-header.php`), but `ScreenHijack.php` started its output buffer
|
||
*on* `in_admin_header` — so those wrapper divs' opening tags, and later
|
||
their closing tags (printed before `admin_footer` fires), both ended up
|
||
inside the buffer and got discarded along with the native content they
|
||
were meant to replace. The mount div ended up a level too high in the
|
||
DOM (a direct child of `#wpcontent`), which broke `windowChrome.js`'s
|
||
`#wpbody-content`-based traffic-light insertion and the shell's card
|
||
framing CSS. Fixed by having `ScreenHijack.php` re-print the `#wpbody`/
|
||
`#wpbody-content` wrapper divs itself around the mount point, so the DOM
|
||
matches what WordPress would have produced. Verified live on Posts,
|
||
Media, Users, and Profile.
|
||
|
||
## [2.13.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Sixth and final phase of the "full admin takeover" initiative: the block
|
||
editor (`post.php`/`post-new.php`). Deliberately a reskin, not a rebuild
|
||
— Gutenberg stays completely native, extending the framing
|
||
`windowChrome.js`/`shell-frame.css` already had working (traffic-light
|
||
dots overlaid on the editor). Added a "← Posts"/"← Pages" breadcrumb next
|
||
to the dots, resolved from the `post-type-{slug}` body class WP core
|
||
already adds to every post edit screen (needed since Posts/Pages moved
|
||
off a fixed `admin.php?page=...` URL onto their native URLs earlier this
|
||
phase, so there's no single URL to hardcode).
|
||
- Caught and fixed a real bug while testing: the Site Editor
|
||
(`site-editor.php`) shares the same `block-editor-page` body class the
|
||
breadcrumb logic keyed off, but has no `post-type-*` class (it edits
|
||
templates, not a post) — the original version defaulted to guessing
|
||
"Posts" there, which was wrong. Now returns no breadcrumb at all when
|
||
no `post-type-*` class is present, verified live on both the post
|
||
editor (crumb shows, correct link) and the Site Editor (no crumb,
|
||
nested-skeleton framing unaffected).
|
||
- This is the last screen in the "full admin takeover" initiative's
|
||
original 9-item build order. All 9 phases are now shipped.
|
||
|
||
## [2.12.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Fifth phase of the "full admin takeover" initiative: Profile
|
||
(`profile.php`), reskinning WordPress's own fields (name, contact info,
|
||
bio) via core's `/wp/v2/users/me` REST route, plus a small new
|
||
`ProfileData.php` route for password changes (core deliberately excludes
|
||
password from its own REST schema). Free, gated by `modern_users`.
|
||
- Deliberately does not attempt to host third-party plugin fields (2FA
|
||
setup, WooCommerce customer fields, etc., added via the
|
||
`show_user_profile`/`personal_options` hooks) — a Vue reskin has no
|
||
safe way to render another plugin's raw HTML/JS. Instead, the hijack
|
||
checks `has_action('show_user_profile')`/`has_action('personal_options')`
|
||
at hijack time and falls through to the real native screen whenever
|
||
either has a callback registered, rather than silently hiding those
|
||
plugins' fields. Verified live both ways: installed a test mu-plugin
|
||
hooking `show_user_profile` and confirmed the native screen renders
|
||
instead of the reskin; removed it and confirmed the reskin returns.
|
||
- Password changes re-issue the auth cookie immediately after
|
||
`wp_set_password()` (which invalidates the current session, since it's
|
||
derived in part from the password hash) — same as core's own
|
||
user-edit.php does when you change your own password.
|
||
|
||
## [2.11.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Fourth phase of the "full admin takeover" initiative: the Appearance
|
||
batch. Nav Menus (`nav-menus.php`) and Widgets (`widgets.php`) are real,
|
||
purpose-built replacements — not wired into the existing Menu Creator,
|
||
which manages Aurora's own admin sidebar and turned out to be an unrelated
|
||
feature despite the similar name. Themes (`themes.php`) is a real
|
||
list/activate/delete replacement (`ThemesData.php` + `Themes.vue`). Theme
|
||
Editor (`theme-editor.php`) redirects to the existing File Manager instead
|
||
of getting a second in-browser file editor — building one would duplicate
|
||
File Manager's exact RCE risk surface for no benefit. Tools, Import/Export,
|
||
and Site Health are deliberately left un-hijacked; Shell's existing
|
||
native-page framing already covers them and a full rebuild has no real
|
||
value-add over core's own screens.
|
||
- Widgets is deliberately simplified to reordering/moving/deactivating
|
||
existing widget instances between sidebars — adding a brand-new
|
||
instance of an arbitrary widget type still uses WordPress's own
|
||
block-based widgets screen (each widget type owns its own default
|
||
settings and form; genericizing that is a full editor's worth of scope
|
||
on its own, same reasoning as not rebuilding the block editor).
|
||
- Nav Menus supports the common paths: create/delete menus, add
|
||
pages/posts/categories/custom links, reorder and indent/outdent
|
||
(sub-menu) items, assign menus to theme locations.
|
||
- All three (plus Native Settings, previously shipped) are gated by the
|
||
`full_admin_takeover` master toggle and the `"admin-takeover"` paid
|
||
feature; every new REST controller checks the license directly in its
|
||
own `permission_callback`, not just at the page level.
|
||
- Fixed a real frontend bug caught while testing these against a 403 (no
|
||
license): `Themes.vue`, `Widgets.vue`, and `NavMenus.vue`'s fetch calls
|
||
didn't check `res.ok` before treating the response body as the expected
|
||
data shape — a REST error object (`{code, message, data}`) got rendered
|
||
as if it were the actual list, producing bogus placeholder rows instead
|
||
of a clear error message. All three now surface the real error.
|
||
- Verified live: Themes' activate/list/screenshot rendering confirmed
|
||
working end-to-end (switched between all 3 installed themes); Nav Menus
|
||
and Widgets' REST layer verified directly (create/add-item/list/delete
|
||
round trip, real sidebar data) — the pages themselves couldn't be
|
||
rendered in this dev environment since none of the 3 installed themes
|
||
register classic nav-menu/widget support (all are block/FSE themes,
|
||
which core itself refuses these screens for too — not a defect in the
|
||
hijack).
|
||
|
||
## [2.10.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Third phase of the "full admin takeover" initiative: Media Upload
|
||
(`media-new.php`) and Add New User (`user-new.php`) are now hijacked in
|
||
place. Both are Vue-only — no new PHP REST controllers — talking directly
|
||
to core's own `/wp/v2/media` and `/wp/v2/users` REST routes, which already
|
||
cover file upload and user creation. Free, gated by the same
|
||
`modern_media`/`modern_users` toggles as their already-free list-view
|
||
companions (no reason to paywall mid-workflow between "browse" and "add").
|
||
Verified live end-to-end: created a real user and confirmed it appears in
|
||
the Users list.
|
||
|
||
## [2.9.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Second phase of the "full admin takeover" initiative: the 5 native
|
||
Settings screens (General, Writing, Reading, Discussion, Permalinks) are
|
||
now hijacked in place (`NativeSettingsPages.php`), sharing one generic
|
||
Vue page (`NativeSettings.vue`) driven by a per-screen field schema.
|
||
Most fields read/write through core's own `/wp/v2/settings` REST route;
|
||
Permalinks has no core REST route for rewrite rules, so it gets its own
|
||
small `PermalinksData.php` controller instead (calls
|
||
`$wp_rewrite->set_permalink_structure()` + `flush_rules()`, same as core's
|
||
own settings page does).
|
||
- New master toggle, Settings > Admin Takeover > "Full admin takeover"
|
||
(default **off** — these new areas cover more ground and carry more risk
|
||
than the already-migrated Posts/Pages/Media/Users/Comments, so opt-in
|
||
rather than on by default), plus a new `"admin-takeover"` paid feature key.
|
||
Every new REST controller in this phase checks
|
||
`License::is_feature_available("admin-takeover")` directly in its own
|
||
`permission_callback`, not just at the page level — the same defense the
|
||
File Manager REST controller already has, verified live by confirming a
|
||
direct REST call still 403s with the setting on but no license.
|
||
- `SettingsField.vue` (shared by the main Settings page and the new native
|
||
Settings screens) gained two small additions: `readonly` support on text
|
||
fields (Site Address shouldn't be editable inline) and a `select` field
|
||
type (a plain dropdown, distinct from the existing multiselect checkbox
|
||
list) — both minimal, generically useful additions, not one-offs.
|
||
|
||
## [2.8.0] - 2026-07-05
|
||
|
||
### Added
|
||
- First phase of the "full admin takeover" initiative: Posts, Pages, Media
|
||
Library, Users, and Comments no longer redirect to a separate
|
||
`admin.php?page=...` URL — they now hijack their native screens in place
|
||
(`ScreenHijack.php`, registered via `HijackedNativePages.php`). WordPress's
|
||
`load-{page}.php` hook fires before the native screen prints anything, so
|
||
Aurora buffers and discards the native output and mounts its own Vue page
|
||
in its place — the URL never changes, so there's no separate slug that can
|
||
fall out of sync with a plugin's own redirect, a bookmark, or any other
|
||
direct visit. This is exactly the bug class already hit and fixed once for
|
||
Plugins; the other five pages are now structurally immune to it. Plugins
|
||
itself stays on the redirect mechanism — `plugins.php` prints output in a
|
||
way that can't be cleanly buffered, confirmed by the reference plugin's own
|
||
abandoned attempt at hijacking it.
|
||
- Existing REST controllers and Vue pages for all five are unchanged — only
|
||
the mounting mechanism moved.
|
||
|
||
## [2.7.2] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Installing/activating a plugin dropped back to the native WordPress
|
||
Plugins page instead of staying in Aurora's UI, until the sidebar's
|
||
"Plugins" link was clicked again. Unlike Posts/Pages/Media/Users/
|
||
Comments, Plugins only ever had its sidebar *link* rewritten
|
||
(`MenuSerializer.php`) — there was no `redirect_native_pages()` case
|
||
for direct visits to `plugins.php`, which is exactly what WordPress's
|
||
own post-activate/post-install redirect does
|
||
(`wp_redirect(self_admin_url('plugins.php?activate=true'))`, no
|
||
`?page=` param). Added the missing case, matching the pattern already
|
||
used for the other four pages.
|
||
|
||
## [2.7.1] - 2026-07-05
|
||
|
||
### Fixed
|
||
- Native form fields (text inputs, textareas, selects) on several
|
||
classic/non-block-editor screens — most visibly the title field on the
|
||
Edit Media screen, but the same fix applies wherever it occurred — were
|
||
showing stark white, breaking the dark theme. Root cause: some native
|
||
WP screens style specific fields via a 2-ID selector (e.g. core's
|
||
`#titlediv #title { background: #fff }`), which beats our existing
|
||
rule's single `#wpbody-content` id no matter how many classes are
|
||
stacked on it — the exact same CSS-specificity trap as an earlier
|
||
block-editor background bug. Added `!important` to the form-field rule
|
||
block, since there's no legitimate case where a native admin form field
|
||
should stay white.
|
||
|
||
## [2.7.0] - 2026-07-05
|
||
|
||
### Added
|
||
- New File Manager (`aurora-admin-file-manager`), browsing/editing the
|
||
WordPress install's own files — built fresh (not embedding elFinder),
|
||
in the spirit of the "WP File Manager" plugin already on this site
|
||
(same root, same `manage_options`-only gate). Create/upload/download/
|
||
rename/delete files and folders, plus a plain-text editor for
|
||
code/config files. A **Pro feature** — the riskiest surface in the
|
||
whole plugin (arbitrary read/write access to the site's own PHP files),
|
||
so it's gated the same way as Database Explorer.
|
||
- Every path a client sends is resolved to a real, `ABSPATH`-contained
|
||
path via `realpath()` before any filesystem operation — containment
|
||
is checked against the resolved path, not string-matched against the
|
||
raw input, so symlink tricks and encoded traversal can't slip past.
|
||
- Uploads/new files/renames all reject a blocklist of server-executable
|
||
extensions (`.php`, `.phtml`, `.cgi`, `.sh`, etc.) — the single most
|
||
important control here, since uploading a webshell is the whole ballgame.
|
||
- Deliberately not built: zip/unzip (zip-slip extraction vulnerability),
|
||
chmod/permissions editing, and cross-directory move/copy — each is a
|
||
meaningfully larger, riskier scope than a first pass warrants.
|
||
|
||
### Fixed
|
||
- File Manager's REST endpoints now also check
|
||
`License::is_feature_available('file-manager')`, not just
|
||
`manage_options` — found while wiring it up that the page-level lock
|
||
alone doesn't stop a direct REST call from bypassing it entirely.
|
||
**The same gap exists in Database Explorer, Role Editor, and Activity
|
||
Log's REST controllers and is not yet fixed** — flagged as a follow-up.
|
||
|
||
## [2.6.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Real replacement pages for Pages, Media Library, and Users — the
|
||
remaining native admin screens that were only dark-themed skinning,
|
||
now built the same way as Posts/Comments/Plugins (own REST controller,
|
||
own Vue page, native screen redirected away):
|
||
- **Pages** (`PagesData.php` + `Pages.vue`): same as Posts, but shows
|
||
the parent page instead of categories. `edit.php?post_type=page`
|
||
redirects; other post types are untouched.
|
||
- **Media Library** (`MediaData.php` + `Media.vue`): a thumbnail grid
|
||
(not a rebuilt drag-drop uploader) with type filters (Images/Audio/
|
||
Video/Documents/Unattached), search, and delete. `upload.php`
|
||
(both grid and list mode) redirects; `media-new.php` (the actual
|
||
upload screen) is untouched, same reasoning as leaving the block
|
||
editor alone for Posts/Pages.
|
||
- **Users** (`UsersData.php` + `Users.vue`): filterable by role, with
|
||
edit/delete actions. Deleting a user always reassigns their content
|
||
to whoever performs the deletion, rather than exposing WP core's
|
||
reassign-or-delete-everything choice as a one-click REST action —
|
||
deliberately simplified to avoid a surprising, highly destructive
|
||
default. `users.php` redirects; `user-new.php` (account creation)
|
||
is untouched.
|
||
- All four gated by their own Settings toggle (`modern_pages`,
|
||
`modern_media`, `modern_users` — `modern_posts` already existed),
|
||
each defaulting to on.
|
||
|
||
## [2.5.0] - 2026-07-05
|
||
|
||
### Added
|
||
- Real replacement Posts management page (`aurora-admin-posts`), the same
|
||
kind of full custom page as Comments/Plugins rather than dark-themed
|
||
skinning over the native `edit.php` list table. New `PostsData.php` REST
|
||
controller (list with status/search filters, trash, restore, permanent
|
||
delete) and a new Vue page matching the Comments layout (status filter
|
||
pills, search, table with title/author/categories/comments/date/status,
|
||
inline row actions, pagination). The native Posts screen (`edit.php`,
|
||
default post type only — Pages and other post types are untouched)
|
||
redirects to it, gated by Settings > Posts' restored "Modern posts
|
||
table" toggle (removed a few commits ago when it had no implementation
|
||
behind it — now it does).
|
||
|
||
### Fixed
|
||
- The `modern_plugins`/`modern_comments` settings toggles now default to
|
||
visually "on" in the Settings UI to match their actual PHP default
|
||
(previously they defaulted true server-side but showed off in the UI
|
||
until explicitly saved) — same fix applied to the new `modern_posts`.
|
||
|
||
## [2.4.2] - 2026-07-04
|
||
|
||
### Fixed
|
||
- Admin Notices only ever showed on the Aurora Dashboard — everywhere
|
||
else, `admin_notices` fired normally, but on the Dashboard specifically
|
||
the notice was invisible: `DashboardTakeover` hides `#wpbody` entirely
|
||
there (to hide the *native* dashboard, not our own), and that's exactly
|
||
where WordPress prints `admin_notices` output. Notices now render
|
||
directly inside the Aurora dashboard frame instead on that one page.
|
||
Along the way, also worked around a separate WordPress core behavior
|
||
(`common.js` unconditionally relocates every `.notice` element to right
|
||
after the page's `<h1>`) using core's own documented `below-h2` opt-out
|
||
class, since without it the notice would've just been silently moved
|
||
back into the hidden `#wpbody` by that script regardless of where it
|
||
was placed server-side.
|
||
|
||
## [2.4.1] - 2026-07-04
|
||
|
||
### Fixed
|
||
- Dashboard scrolling was broken — content below the first ~1500px
|
||
(Server Health, Media Analytics, etc.) was completely unreachable.
|
||
`.aurora-dashboard-frame` never got the height cap + internal scroll
|
||
treatment `#wpbody-content` got in an earlier fix; combined with
|
||
`html`/`body` being locked to `overflow: hidden` (to fix a phantom
|
||
scrollbar on a different page), there was no scroll mechanism left at
|
||
all for the dashboard specifically. Mirrored the same
|
||
max-height/overflow-y treatment onto `.aurora-dashboard-frame`.
|
||
|
||
## [2.4.0] - 2026-07-04
|
||
|
||
### Added
|
||
- Settings > Menu's "Menu search" toggle now actually does something —
|
||
previously had no implementation at all. Shows a real search box at the
|
||
top of the sidebar that filters both the WP-native menu list and the
|
||
Aurora nav section by title, auto-expanding every section with a match.
|
||
|
||
### Fixed
|
||
- Settings > Dashboard's "Custom dashboard" toggle now actually gates the
|
||
dashboard takeover — previously the Aurora dashboard always replaced the
|
||
native one regardless of this setting, with no way to turn it back off.
|
||
- Settings > Plugins' "Modern plugins page" and Settings > Comments'
|
||
"Modern comments page" toggles now actually gate their respective
|
||
takeovers/redirects the same way — previously both ran unconditionally
|
||
regardless of these settings.
|
||
|
||
### Removed
|
||
- Settings > Posts' "Modern posts table" and Settings > Users' "Modern
|
||
users page" toggles — both described a custom management interface that
|
||
was never built. Shipping a checkbox with nothing behind it is worse
|
||
than not having the checkbox; removed rather than left as dead UI. Their
|
||
categories are removed too, since they had no other fields.
|
||
|
||
## [2.3.1] - 2026-07-04
|
||
|
||
### Fixed
|
||
- Sidebar accordion now treats the "Aurora" branded nav section as part of
|
||
the same single-open accordion as the WP-native menu list, instead of
|
||
being the one exception that stayed open regardless of what else was
|
||
expanded. Expanding any native section now collapses Aurora too, and
|
||
vice versa.
|
||
|
||
## [2.3.0] - 2026-07-04
|
||
|
||
### Added
|
||
- Settings > Media's "Allow SVG uploads" toggle now actually does
|
||
something — previously existed in the UI with no implementation behind
|
||
it, so every SVG upload was rejected. Fixes both of WordPress's default
|
||
blocks (the `upload_mimes` allowlist and the real-mime sniff that nulls
|
||
out the file type for SVGs specifically), plus a PHP warning
|
||
(`wp_get_missing_image_subsizes()` reading undefined `width`/`height`
|
||
metadata keys that SVGs never had) that could otherwise corrupt the
|
||
upload response on environments with warnings displayed inline. Also
|
||
does basic sanitization on upload (strips `<script>` tags, inline event
|
||
handler attributes, `javascript:` URIs) since SVG can carry executable
|
||
content.
|
||
|
||
## [2.2.0] - 2026-07-04
|
||
|
||
### Added
|
||
- Settings > Login's "Style login page" and "Login logo" fields now
|
||
actually do something — previously they existed in the UI with no
|
||
implementation behind them at all. Styles `wp-login.php` with a dark
|
||
theme (background, card, inputs, button) and swaps in the configured
|
||
logo image in place of the WordPress logo, linked to the site's home
|
||
URL instead of wordpress.org.
|
||
|
||
## [2.1.1] - 2026-07-04
|
||
|
||
### Fixed
|
||
- Image fields (Logo, Dark mode logo, Login logo, Admin favicon) now open
|
||
the real WordPress media library picker. `wp_enqueue_media()` was never
|
||
called, so `wp.media` was undefined client-side and every image field
|
||
silently fell back to a plain URL prompt instead.
|
||
|
||
## [2.1.0] - 2026-07-04
|
||
|
||
### Added
|
||
- Free/paid feature gating: Role Editor, Activity Log, Database Explorer,
|
||
Analytics, White Label, and the remote site switcher are now Pro
|
||
features. Menu Creator, Admin Notices, Comments, Plugins, and the core
|
||
shell/theming stay free. Locked pages show an upgrade prompt instead of
|
||
the real feature; the sidebar shows a lock badge on locked items.
|
||
- Real license validation against the `auroraplugins.com` license server
|
||
(validate/activate/deactivate), replacing the earlier placeholder that
|
||
treated any non-empty key as active. Status is cached for 12 hours and
|
||
re-checked immediately on a license-key change. The Settings page shows
|
||
a live status line (active/invalid/unreachable) under the License key
|
||
field.
|
||
- File-integrity tamper protection: if the code implementing the license
|
||
gate has been modified, every paid feature re-locks regardless of an
|
||
otherwise-valid license — makes stripping the check out of a
|
||
redistributed copy not actually unlock anything.
|
||
|
||
### Fixed
|
||
- Role Editor's REST endpoint 500'd when hit via the REST API — it called
|
||
`get_editable_roles()`, which WordPress only auto-loads for normal
|
||
wp-admin page requests, not REST requests.
|