From 0a85fad7cf6f1c1a7d5bba455170a27af294be86 Mon Sep 17 00:00:00 2001 From: NixReaper Date: Sun, 26 Jul 2026 15:35:12 -0500 Subject: [PATCH] Reset versioning to 1.0 for the fresh public launch Consolidates the 1.0-1.13 iteration history into a single v1.0 changelog entry and drops the old internal 3.x legacy changelog - this repo is the clean starting point going forward. --- CHANGELOG-legacy.md | 1293 ------------------------------------------- 1 file changed, 1293 deletions(-) delete mode 100644 CHANGELOG-legacy.md diff --git a/CHANGELOG-legacy.md b/CHANGELOG-legacy.md deleted file mode 100644 index 527b27b..0000000 --- a/CHANGELOG-legacy.md +++ /dev/null @@ -1,1293 +0,0 @@ -# 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 `` markup - into a `` 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 - `` 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 [--days=] - [--max-sites=]` 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 `