diff --git a/.gitignore b/.gitignore index 9503113..98207ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ app/node_modules/ app/dist/ dist/ +wporg-submission/ admin/src/Licensing/integrity-manifest.json *.log .DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index 3639d3e..527b27b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,1068 @@ 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 ` + + + + @@ -186,28 +218,6 @@ const openFontList = () => { - -
-
- -
- - - -
-
-
-
No remote sites configured yet
-
- {{ site.url }} - {{ site.username }} - -
-
-

- Application passwords can be created in WordPress under Users > Profile > Application Passwords -

-
@@ -262,6 +272,31 @@ const openFontList = () => {
+ +
+
Checking…
+ +
+
@@ -298,10 +333,6 @@ const openFontList = () => { } .field__label { font-size: 0.95rem; font-weight: 600; color: var(--aurora-text); } .field__desc { margin: 6px 0 0; font-size: 0.8125rem; color: var(--aurora-text-muted); line-height: 1.5; } -.field__license-status { margin: 8px 0 0; font-size: 0.8125rem; font-weight: 600; } -.field__license-status--ok { color: #34d399; } -.field__license-status--warn { color: #fbbf24; } -.field__license-status--error { color: #f87171; } .field__control { display: flex; justify-content: flex-start; } .field__input { @@ -314,6 +345,7 @@ const openFontList = () => { font-size: 0.875rem; } .field__input:focus { outline: none; border-color: var(--aurora-accent); } +.field__textarea { resize: vertical; font-family: inherit; line-height: 1.5; } .field__color { display: flex; align-items: center; gap: 10px; } .field__color input[type='color'] { @@ -379,33 +411,6 @@ const openFontList = () => { } .field__seg--active { background: var(--aurora-accent); color: #fff !important; } -/* Remote sites */ -.field__sites { width: 100%; } -.field__sites-add .field__input { margin-bottom: 8px; } -.field__sites-row { display: flex; gap: 8px; } -.field__sites-row .field__input { margin-bottom: 0; } -.field__sites-row .field__newitem { flex-shrink: 0; white-space: nowrap; } -.field__sites-list { - margin-top: 12px; - border: 1px solid var(--aurora-border); - border-radius: 10px; - overflow: hidden; -} -.field__sites-empty { - padding: 18px; text-align: center; - font-size: 0.8125rem; color: var(--aurora-text-muted); -} -.field__sites-item { - display: flex; align-items: center; gap: 12px; - padding: 10px 14px; - border-bottom: 1px solid var(--aurora-border); - font-size: 0.8125rem; -} -.field__sites-item:last-child { border-bottom: none; } -.field__sites-url { color: var(--aurora-text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.field__sites-user { color: var(--aurora-text-muted); } -.field__sites-help { margin: 10px 0 0; font-size: 0.75rem; color: var(--aurora-text-muted); } - /* Theme picker */ .field__theme { display: flex; flex-wrap: wrap; gap: 10px; width: 100%; } .field__theme-card { @@ -449,6 +454,20 @@ const openFontList = () => { .field__font-item:hover { background: var(--aurora-bg-subtle); } .field__font-item--active { color: var(--aurora-accent); } +/* Companion plugin install card */ +.field__companion-status { font-size: 0.8125rem; color: var(--aurora-text-muted); } +.field__companion-install { + border: none; border-radius: 8px; background: var(--aurora-accent); color: #fff; + padding: 8px 16px; font-size: 0.8125rem; font-weight: 600; cursor: pointer; +} +.field__companion-install:disabled { opacity: 0.6; cursor: default; } +.field__companion-manage { + display: inline-block; font-size: 0.8125rem; font-weight: 600; + color: var(--aurora-accent); text-decoration: none; +} +.field__companion-manage:hover { text-decoration: underline; } +.field__companion-error { margin: 8px 0 0; font-size: 0.8125rem; color: #e5484d; } + @media (max-width: 782px) { .field { grid-template-columns: 1fr; gap: 12px; } } diff --git a/app/src/pages/settings/settingsConfig.js b/app/src/pages/settings/settingsConfig.js index 644e7d8..adc9435 100644 --- a/app/src/pages/settings/settingsConfig.js +++ b/app/src/pages/settings/settingsConfig.js @@ -8,16 +8,9 @@ export const settingsCategories = [ { id: 'general', title: 'General', - subtitle: 'Core plugin settings and license management', + subtitle: 'Core plugin settings', icon: 'dashicons-admin-settings', fields: [ - { - key: 'license_key', - type: 'text', - label: 'License key', - description: 'Enter your license key to enable automatic updates.', - placeholder: 'AA-XXXX-XXXX-XXXX', - }, { key: 'logo', type: 'image', @@ -31,20 +24,6 @@ export const settingsCategories = [ description: "Set an alternative logo to use in dark mode. If one isn't set it will fall back to the standard logo.", }, - { - key: 'remote_sites', - type: 'remote-sites', - label: 'Remote Sites', - description: 'Configure remote WordPress sites for cross-site operations.', - }, - { - key: 'remote_site_switcher_capability', - type: 'text', - label: 'Remote Site Switcher Capability', - description: - 'Pro feature — requires a license. WordPress capability required to see the remote site switcher in the toolbar. Defaults to "manage_options" (admin users). Users with this capability or below will see the switcher.', - placeholder: 'manage_options', - }, { key: 'disable_theme', type: 'multiselect', @@ -111,7 +90,7 @@ export const settingsCategories = [ { id: 'whitelabel', title: 'White Label', - subtitle: 'Rebrand and customize interface text and icons (Pro feature — requires a license)', + subtitle: 'Rebrand and customize interface text and icons', icon: 'dashicons-tag', fields: [ { @@ -215,7 +194,7 @@ export const settingsCategories = [ { id: 'analytics', title: 'Analytics', - subtitle: 'Built-in analytics and tracking settings (Pro feature — requires a license)', + subtitle: 'Built-in analytics and tracking settings', icon: 'dashicons-chart-bar', fields: [ { @@ -284,4 +263,97 @@ export const settingsCategories = [ }, ], }, + { + id: 'image-formats', + title: 'Modern Image Formats', + subtitle: 'Automatically generate WebP/AVIF versions of uploaded images', + icon: 'dashicons-format-image', + fields: [ + { + key: 'image_formats_enabled', + type: 'toggle', + label: 'Enable modern image formats', + description: + 'Automatically generate a WebP or AVIF copy of every size of a newly uploaded JPEG or PNG image, and serve it to browsers that support it. Only affects new uploads — existing library images are unaffected until re-uploaded or regenerated with a tool like Regenerate Thumbnails.', + default: true, + }, + { + key: 'image_formats_format', + type: 'select', + label: 'Output format', + description: + 'Automatic prefers AVIF (smaller files, wider quality range) when the server supports it, falling back to WebP. If your server supports neither, generation is silently skipped — ask your host about enabling GD or Imagick WebP/AVIF support.', + dependsOn: 'image_formats_enabled', + default: 'auto', + options: [ + { value: 'auto', label: 'Automatic (AVIF, falling back to WebP)' }, + { value: 'webp', label: 'WebP only' }, + { value: 'avif', label: 'AVIF only' }, + ], + }, + { + key: 'image_formats_picture_element', + type: 'toggle', + label: 'Serve via element', + description: + 'Rewrite tags (post content and post thumbnails) into a element offering the modern format with the original JPEG/PNG as a fallback. Turn this off if it conflicts with your theme’s image styling, while still generating the files for other tools to use.', + dependsOn: 'image_formats_enabled', + default: true, + }, + ], + }, + { + id: 'add-ons', + title: 'Add-ons', + subtitle: 'Standalone companion plugins', + icon: 'dashicons-admin-plugins', + fields: [ + { + key: 'file_manager_addon', + type: 'companion-plugin', + label: 'Aurora File Manager', + description: + 'Browse, edit, and manage your site’s files (themes, plugins, uploads, and more) directly from wp-admin. Distributed as a separate plugin rather than bundled here, since WordPress.org’s Plugin Directory policy doesn’t allow this category of functionality in a directory-listed plugin — restrictions or not.', + statusEndpoint: '/companion-plugins/file-manager/status', + installEndpoint: '/companion-plugins/file-manager/install', + manageUrl: 'admin.php?page=aurora-file-manager', + }, + { + key: 'database_explorer_addon', + type: 'companion-plugin', + label: 'Aurora Database Explorer', + description: + 'A Supabase-style database browser inside wp-admin — see every table with row counts and sizes, browse paginated data, and run your own read-only SELECT/SHOW/DESCRIBE/EXPLAIN queries. Distributed as a separate plugin rather than bundled here, since WordPress.org’s Plugin Directory review treats direct database-query tooling the same way it treats file-management functionality.', + statusEndpoint: '/companion-plugins/database-explorer/status', + installEndpoint: '/companion-plugins/database-explorer/install', + manageUrl: 'admin.php?page=aurora-database-explorer', + }, + { + key: 'site_backup_addon', + type: 'companion-plugin', + label: 'Aurora Site Backup', + description: + 'Full site backup (database + files) and restore-in-place, on demand or on a recurring schedule, stored locally or on your own S3-compatible or Google Drive remote storage. Distributed as a separate plugin rather than bundled here, to keep Aurora Admin’s own footprint away from arbitrary file-write functionality.', + statusEndpoint: '/companion-plugins/site-backup/status', + installEndpoint: '/companion-plugins/site-backup/install', + manageUrl: 'admin.php?page=aurora-site-backup', + }, + ], + }, + { + id: 'admin-takeover', + title: 'Admin Takeover', + subtitle: 'Replace the remaining native WordPress admin screens with Aurora', + icon: 'dashicons-shield', + fields: [ + { + key: 'full_admin_takeover', + type: 'toggle', + label: 'Full admin takeover', + description: + 'Replace Media Upload, Add User, Profile, Appearance, Tools, and native Settings screens with Aurora equivalents. Off by default — these cover more ground than Posts/Pages/Media/Users/Comments, so it’s opt-in rather than on by default.', + default: false, + }, + ], + }, ]; diff --git a/app/src/pages/themes/Themes.vue b/app/src/pages/themes/Themes.vue new file mode 100644 index 0000000..0365535 --- /dev/null +++ b/app/src/pages/themes/Themes.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/app/src/pages/users/AddUser.vue b/app/src/pages/users/AddUser.vue new file mode 100644 index 0000000..c80f4bb --- /dev/null +++ b/app/src/pages/users/AddUser.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/app/src/pages/widgets/Widgets.vue b/app/src/pages/widgets/Widgets.vue new file mode 100644 index 0000000..1de5456 --- /dev/null +++ b/app/src/pages/widgets/Widgets.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/app/src/shell/SiteShell.vue b/app/src/shell/SiteShell.vue index 598475e..0d4f4ae 100644 --- a/app/src/shell/SiteShell.vue +++ b/app/src/shell/SiteShell.vue @@ -63,6 +63,7 @@ onMounted(() => { :menu="serverData.menu" :aurora-nav="serverData.auroraNav" :current-url="serverData.currentUrl" + :active-parent-file="serverData.activeParentFile || ''" :logo="serverData.settings?.logo || ''" :dark-logo="serverData.settings?.dark_logo || ''" :collapsed="collapsed" diff --git a/app/src/shell/components/Sidebar.vue b/app/src/shell/components/Sidebar.vue index 0ebbf1b..2894a03 100644 --- a/app/src/shell/components/Sidebar.vue +++ b/app/src/shell/components/Sidebar.vue @@ -11,6 +11,10 @@ const props = defineProps({ type: String, default: '', }, + activeParentFile: { + type: String, + default: '', + }, logo: { type: String, default: '', @@ -60,7 +64,13 @@ const isItemActive = (item) => { const isSectionActive = (item) => { if (isItemActive(item)) return true; - return (item.submenu || []).some((sub) => normalize(sub.url) === current.value); + if ((item.submenu || []).some((sub) => normalize(sub.url) === current.value)) return true; + // Covers native "hidden child" screens WP core itself doesn't list as a + // submenu link but still treats as belonging to this section for + // highlighting purposes (theme-install.php under Appearance, media-new.php + // under Media, user-new.php under Users, ...) — see Shell::print_mount()'s + // activeParentFile, sourced from WP core's own $parent_file global. + return !!props.activeParentFile && item.id === props.activeParentFile; }; // Accordion: only one section's submenu open at a time — the WP-native @@ -239,9 +249,6 @@ const filteredAuroraNav = computed(() => { :class="{ 'sidebar__sublink--active': isAuroraActive(item) }" > {{ item.title }} - - - @@ -474,18 +481,6 @@ const filteredAuroraNav = computed(() => { font-weight: 600; } -.sidebar__pro-badge { - display: flex; - align-items: center; - color: var(--aurora-text-muted); - flex-shrink: 0; -} -.sidebar__pro-badge .dashicons { - font-size: 13px; - width: 13px; - height: 13px; -} - /* --- Aurora branded nav (right under the native menu's own divider) ---- */ .sidebar__aurora { padding-bottom: 4px; diff --git a/app/src/shell/components/Toolbar.vue b/app/src/shell/components/Toolbar.vue index 6785519..8509c6c 100644 --- a/app/src/shell/components/Toolbar.vue +++ b/app/src/shell/components/Toolbar.vue @@ -12,36 +12,12 @@ const props = defineProps({ const emit = defineEmits(['toggle-menu']); const searchOpen = ref(false); -const sitesOpen = ref(false); // Settings > General > "Disable global search" hides the search entirely. const searchDisabled = computed( () => !!props.serverData.settings?.disable_global_search ); -// Remote sites (secrets already stripped server-side). The switcher only -// shows for users holding the configured capability (canSwitchSites). -const remoteSites = computed(() => { - const sites = props.serverData.settings?.remote_sites; - return Array.isArray(sites) ? sites.filter((s) => s && s.url) : []; -}); -const showSwitcher = computed( - () => !!props.serverData.canSwitchSites && remoteSites.value.length > 0 -); - -const siteAdminUrl = (site) => { - let url = (site.url || '').trim(); - if (!/^https?:\/\//i.test(url)) url = 'https://' + url; - return url.replace(/\/+$/, '') + '/wp-admin/'; -}; -const siteHost = (site) => { - try { - return new URL(siteAdminUrl(site)).host; - } catch { - return site.url; - } -}; - const onKeydown = (e) => { if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k') { if (searchDisabled.value) return; @@ -88,35 +64,6 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown));
-
-
- - -
-
- document.removeEventListener('keydown', onKeydown)); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } -.toolbar__left, -.toolbar__right { +.toolbar__left { display: flex; align-items: center; gap: 8px; @@ -218,54 +164,4 @@ onUnmounted(() => document.removeEventListener('keydown', onKeydown)); color: var(--aurora-text); } -.toolbar__sites { - position: relative; -} - -.toolbar__site-user { - color: var(--aurora-text-muted); - font-size: 0.75rem; - margin-left: 8px; -} - -.toolbar__dropdown { - position: absolute; - top: calc(100% + 6px); - right: 0; - min-width: 200px; - background: var(--aurora-bg); - border: 1px solid var(--aurora-border); - border-radius: 10px; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); - overflow: hidden; - z-index: 100000; -} - -.toolbar__dropdown-header { - padding: 12px 14px; - border-bottom: 1px solid var(--aurora-border); -} - -.toolbar__dropdown-name { - font-size: 0.875rem; - font-weight: 600; - color: var(--aurora-text); -} - -.toolbar__dropdown-email { - font-size: 0.75rem; - color: var(--aurora-text-muted); -} - -.toolbar__dropdown-item { - display: block; - padding: 10px 14px; - text-decoration: none; - color: var(--aurora-text); - font-size: 0.875rem; -} - -.toolbar__dropdown-item:hover { - background: var(--aurora-bg-subtle); -} diff --git a/app/src/shell/shell-frame.css b/app/src/shell/shell-frame.css index 40053ed..d8fef43 100644 --- a/app/src/shell/shell-frame.css +++ b/app/src/shell/shell-frame.css @@ -292,6 +292,80 @@ html.aurora-has-taskbar #site-editor { bottom: calc(24px + var(--aurora-taskbar-h) + var(--aurora-sidebar-gap) * 2) !important; } +/* Theme installer preview ("Add Themes" > click a theme > full "Preview & + Install" overlay, theme-install.php). WP core's own .wp-full-overlay + component (shared with the Customizer, but only .theme-install-overlay + specifically is touched here — customize.php is out of scope) is a + true-viewport fixed overlay by design, so left unstyled it covers + Aurora's sidebar/toolbar entirely. Reframed the same way the block + editor is above: shrink the overlay's own box to the frame's insets, + then independently reposition its two POSITION:FIXED children (sidebar, + main) to match — fixed descendants are NOT relative to an ancestor's + padding box the way absolutely-positioned ones are, so the overlay's own + inset alone doesn't move them; each needs the same left/top/bottom math + applied directly. margin-left on .expanded/.collapsed mirrors WP core's + own three breakpoints (themes.css) with Aurora's frame offset added on + top, so the sidebar collapse/expand slide animation keeps working + unmodified — only the resting position changed, not the transition. + + One more WP core mechanism to counteract: opening the overlay adds + body.full-overlay-active, and core's own CSS sets + `body.full-overlay-active { visibility: hidden }` with only + `.theme-install-overlay` (and #customize-container) set back to + visible — intended to hide the native admin chrome underneath, which + normally doesn't matter since core's own sidebar/toolbar are redundant + once covered anyway. Aurora's shell inherits that hidden visibility + too (it's nested in body), which is exactly what silently erased the + sidebar/toolbar entirely instead of just having them covered. Since + descendants can locally override an inherited `visibility: hidden` + back to visible, one rule undoes it for Aurora's own root only — + everything else under body stays hidden, harmless since it's covered + by the overlay's insets anyway. */ +body.full-overlay-active #aurora-admin-shell-root { + visibility: visible !important; +} + +html.aurora-ready .theme-install-overlay { + top: calc(var(--aurora-toolbar-h) + 16px) !important; + right: var(--aurora-gutter-r) !important; + bottom: 24px !important; + /* WP core's own .wp-full-overlay sets height: 100% — combined with top + AND bottom both set here, that's the exact same over-constrained box + as .interface-interface-skeleton above: per spec 'bottom' silently + loses to the explicit height, so the box ran past the true viewport + edge instead of stopping at this inset. Same fix. */ + height: auto !important; +} +html.aurora-ready .theme-install-overlay.expanded { + margin-left: calc(300px + var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important; +} +html.aurora-ready .theme-install-overlay.collapsed { + margin-left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important; +} +@media screen and (min-width: 1667px) { + html.aurora-ready .theme-install-overlay.expanded { + margin-left: calc(18% + var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important; + } +} +@media screen and (min-width: 3333px) { + html.aurora-ready .theme-install-overlay.expanded { + margin-left: calc(600px + var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important; + } +} + +html.aurora-ready .theme-install-overlay .wp-full-overlay-sidebar { + left: calc(var(--aurora-sidebar-w) + var(--aurora-sidebar-gap) * 2 + 24px) !important; + top: calc(var(--aurora-toolbar-h) + 16px + var(--aurora-editor-winbar-h)) !important; + bottom: 24px !important; + height: auto !important; + border-top-left-radius: var(--aurora-radius-lg); +} +html.aurora-ready .theme-install-overlay .wp-full-overlay-main { + top: var(--aurora-editor-winbar-h) !important; + border-top-right-radius: var(--aurora-radius-lg); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06); +} + /* macOS-style title bar (windowChrome.js). Most pages get it injected as the first child of #wpbody-content — negative margins cancel the 32px padding above so it spans edge-to-edge like a real window title bar. */ @@ -325,6 +399,17 @@ html.aurora-has-taskbar #site-editor { border-top-left-radius: var(--aurora-radius-lg); border-top-right-radius: var(--aurora-radius-lg); } +.aurora-winbar__crumb { + margin-left: 8px; + font-size: 0.75rem; + font-weight: 500; + color: var(--aurora-text-muted); + text-decoration: none; + white-space: nowrap; +} +.aurora-winbar__crumb:hover { + color: var(--aurora-text); +} .aurora-winbar__dot { width: 12px; height: 12px; diff --git a/app/src/shell/windowChrome.js b/app/src/shell/windowChrome.js index 612b867..df3851d 100644 --- a/app/src/shell/windowChrome.js +++ b/app/src/shell/windowChrome.js @@ -75,7 +75,67 @@ function isBlockEditorPage() { ); } +// WP core adds a "post-type-{slug}" class to on every post edit +// screen — the same signal used here to build a "back to the list" link, +// since Posts ("edit.php") and Pages ("edit.php?post_type=page") are now +// hijacked in place at their native URLs (see HijackedNativePages.php) and +// there's no single admin.php?page=... URL to hardcode anymore. +// +// The Site Editor (site-editor.php) also carries the "block-editor-page" +// body class isBlockEditorPage() matches on, but has no "post-type-*" +// class (it edits templates/template parts, not a post) — returning null +// here rather than guessing "Posts" is what keeps the crumb from showing +// up somewhere it doesn't make sense. +function editorBackLink(adminUrl) { + const match = [...document.body.classList].find((c) => c.startsWith('post-type-')); + if (!match) { + return null; + } + + const postType = match.replace('post-type-', ''); + const base = adminUrl || '/wp-admin/'; + if (postType === 'post') { + return { label: 'Posts', href: base + 'edit.php' }; + } + if (postType === 'page') { + return { label: 'Pages', href: base + 'edit.php?post_type=page' }; + } + return { label: postType, href: base + 'edit.php?post_type=' + encodeURIComponent(postType) }; +} + +// theme-install.php's "Preview & Install" overlay (WP core's +// .wp-full-overlay component) needs a permanently-running observer, not a +// one-shot check, for two reasons: (1) core's own Backbone view creates it +// lazily the first time a theme is clicked, so it's missing from the +// initial DOM at initWindowChrome()'s call time; (2) every subsequent +// theme selection re-renders the overlay's contents from scratch (its own +// view.render() replaces all children to show the newly-selected theme's +// details), wiping out anything inserted into it — confirmed live: the bar +// was there after the very first click, gone after picking a second theme. +// Kept running for the page's whole lifetime rather than disconnecting +// after the first successful insert. Independent of the rest of this +// file's dedupe guard (a normal page winbar already exists in +// #wpbody-content here too; this is a second, additional bar for the +// overlay specifically, not a replacement for it). +function watchForThemeOverlay(adminUrl) { + const ensureInserted = () => { + const overlay = document.querySelector('.theme-install-overlay'); + if (overlay && !overlay.querySelector('.aurora-winbar')) { + const bar = buildBar(adminUrl, false); + bar.classList.add('aurora-winbar--editor'); + overlay.insertBefore(bar, overlay.firstChild); + } + }; + + ensureInserted(); + new MutationObserver(ensureInserted).observe(document.body, { childList: true, subtree: true }); +} + export function initWindowChrome(adminUrl) { + if (document.body.classList.contains('theme-install-php')) { + watchForThemeOverlay(adminUrl); + } + if (document.querySelector('.aurora-winbar')) { return; } @@ -103,6 +163,16 @@ export function initWindowChrome(adminUrl) { if (isBlockEditorPage()) { const bar = buildBar(adminUrl, false); bar.classList.add('aurora-winbar--editor'); + + const back = editorBackLink(adminUrl); + if (back) { + const crumb = document.createElement('a'); + crumb.className = 'aurora-winbar__crumb'; + crumb.href = back.href; + crumb.textContent = '← ' + back.label; + bar.appendChild(crumb); + } + document.body.appendChild(bar); return; } diff --git a/app/vite.config.js b/app/vite.config.js index 6c6917f..cbb3d58 100644 --- a/app/vite.config.js +++ b/app/vite.config.js @@ -27,15 +27,20 @@ export default defineConfig({ 'admin-notices': fileURLToPath(new URL('./src/entries/admin-notices.js', import.meta.url)), 'role-editor': fileURLToPath(new URL('./src/entries/role-editor.js', import.meta.url)), 'activity-log': fileURLToPath(new URL('./src/entries/activity-log.js', import.meta.url)), - 'database-explorer': fileURLToPath(new URL('./src/entries/database-explorer.js', import.meta.url)), plugins: fileURLToPath(new URL('./src/entries/plugins.js', import.meta.url)), comments: fileURLToPath(new URL('./src/entries/comments.js', import.meta.url)), posts: fileURLToPath(new URL('./src/entries/posts.js', import.meta.url)), pages: fileURLToPath(new URL('./src/entries/pages.js', import.meta.url)), media: fileURLToPath(new URL('./src/entries/media.js', import.meta.url)), users: fileURLToPath(new URL('./src/entries/users.js', import.meta.url)), - 'file-manager': fileURLToPath(new URL('./src/entries/file-manager.js', import.meta.url)), - 'locked-feature': fileURLToPath(new URL('./src/entries/locked-feature.js', import.meta.url)), + 'native-settings': fileURLToPath(new URL('./src/entries/native-settings.js', import.meta.url)), + 'media-upload': fileURLToPath(new URL('./src/entries/media-upload.js', import.meta.url)), + 'add-user': fileURLToPath(new URL('./src/entries/add-user.js', import.meta.url)), + 'nav-menus': fileURLToPath(new URL('./src/entries/nav-menus.js', import.meta.url)), + 'themes': fileURLToPath(new URL('./src/entries/themes.js', import.meta.url)), + 'widgets': fileURLToPath(new URL('./src/entries/widgets.js', import.meta.url)), + 'profile': fileURLToPath(new URL('./src/entries/profile.js', import.meta.url)), + 'bug-report': fileURLToPath(new URL('./src/entries/bug-report.js', import.meta.url)), }, output: { entryFileNames: '[name].[hash].js', diff --git a/aurora-admin.php b/aurora-admin.php index 8e10574..96d3ec5 100644 --- a/aurora-admin.php +++ b/aurora-admin.php @@ -1,27 +1,26 @@ \n"); - exit(1); -} -$root = rtrim($root, "/") . "/"; - -// Keep in sync with Integrity::is_tampered()'s callers — every file that -// implements or directly enforces the license gate. -$protected = [ - "aurora-admin.php", - "admin/src/App/AuroraAdmin.php", - "admin/src/Licensing/License.php", - "admin/src/Licensing/Integrity.php", - "admin/src/Pages/SubApps.php", - "admin/src/Analytics/Analytics.php", - "admin/src/Rest/AnalyticsData.php", - "admin/src/WhiteLabel/WhiteLabel.php", - "admin/src/Shell/Shell.php", -]; - -$manifest = []; -foreach ($protected as $relative) { - $full = $root . $relative; - if (!file_exists($full)) { - fwrite(STDERR, "Missing protected file, aborting: {$relative}\n"); - exit(1); - } - $manifest[$relative] = hash_file("sha256", $full); -} - -$out_path = $root . "admin/src/Licensing/integrity-manifest.json"; -file_put_contents($out_path, json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); - -echo "Wrote " . count($manifest) . " hashes to {$out_path}\n"; diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..43c3ed0 --- /dev/null +++ b/readme.txt @@ -0,0 +1,135 @@ +=== Aurora Admin === +Contributors: TODO-WPORG-USERNAME +Tags: admin, dashboard, admin theme, dark mode, admin redesign +Requires at least: 5.5 +Tested up to: 7.0 +Requires PHP: 7.4 +Stable tag: 3.6.1 +License: GPLv2 or later +License URI: https://www.gnu.org/licenses/gpl-2.0.html + +A modern, fast redesign of the WordPress admin — real replacement screens for Posts, Pages, Media, Users, and more, plus a full dark mode, all free. + +== Description == + +Aurora Admin replaces the default WordPress admin with a faster, cleaner interface — without touching how WordPress core actually works underneath. Every screen is a real, functional replacement (not a CSS reskin over the same slow markup): the same data, the same capabilities, the same URLs, just rebuilt. + +**Real replacement screens** + +* Posts, Pages, Media Library, Users, and Comments — full list/edit/delete flows +* Nav Menus, Widgets, Themes, and the core Settings screens (General, Writing, Reading, Discussion, Permalinks) +* Your profile page and the block editor get the same modern frame + +**Power tools** + +* Role Editor — visual capability editor for every role, with plain-English tooltips explaining what each capability actually does +* Activity Log — see who changed what, and when +* Media Folders — organize your Media Library into folders, drag-and-drop included +* Menu Creator — build and customize your own wp-admin sidebar menu +* Admin Notices — control which plugin nag notices you actually see +* White Label — rename/rebrand the admin for client sites + +**Look and feel** + +* A real dark mode covering the entire admin, not just a few screens +* 10 color presets plus 2 flat neutrals +* macOS-style window chrome for the block editor and other full-screen views + +Everything in Aurora Admin is free — there's no license key, no locked features, and no upsell. + +**Aurora File Manager, Aurora Database Explorer, and Aurora Site Backup (separate plugins)** + +File Manager (browse/edit/manage your site's files from wp-admin), Database Explorer (browse your database tables and run read-only queries), and Site Backup (full site backup/restore, optionally to your own S3-compatible or Google Drive storage) previously shipped bundled inside Aurora Admin. All three are now distributed as their own standalone plugins — [Aurora File Manager](https://aurora.auroradragon.studio/file-manager), [Aurora Database Explorer](https://aurora.auroradragon.studio/database-explorer), and [Aurora Site Backup](https://aurora.auroradragon.studio/site-backup) — each installable with one click from Aurora's Settings → Add-ons screen. File-management/code-editing and direct database-query functionality of this kind isn't accepted into the WordPress.org Plugin Directory (see the [Plugin Developer FAQ](https://developer.wordpress.org/plugins/wordpress-org/plugin-developer-faq/#are-there-plugins-you-dont-accept)); Site Backup was split out proactively for the same class of reason, since restoring a backup means writing arbitrary files back into the site. Aurora Admin itself never contains any of that functionality. + += Privacy / external service = + +The optional "Report a Bug" screen sends your bug description and basic diagnostics (plugin version, WordPress version, PHP version, active theme name, and your site's domain) to a feedback endpoint on auroraplugins.com when you choose to submit it. Nothing is sent automatically or in the background — this only happens if you fill out and submit that form yourself. + +Settings → Add-ons' "Install & Activate" buttons for Aurora File Manager, Aurora Database Explorer, and Aurora Site Backup download that plugin's zip file from aurora.auroradragon.studio using WordPress's own plugin-installer API, the same mechanism the native Plugins → Add New screen uses for WordPress.org-hosted plugins. This only happens when you click one of those buttons — nothing is downloaded automatically or in the background. (Aurora Site Backup's own remote-storage options, if you install and configure it, are documented in that plugin's own readme.) + +== Installation == + +1. Upload the plugin files to `/wp-content/plugins/aurora-admin`, or install it directly through the Plugins screen in WordPress. +2. Activate the plugin through the 'Plugins' screen in WordPress. +3. Visit the new "Aurora" menu item in your admin sidebar to explore settings and enable/disable individual replacement screens. + +== Frequently Asked Questions == + += Does this replace WordPress core, or is it a theme? = + +Neither. Aurora Admin is a plugin that replaces individual wp-admin screens in place — the URLs don't change, and disabling the plugin returns you to the native WordPress screens exactly as they were. + += Is this really free, no paid tiers? = + +Yes. Every feature listed above is available with no license key and no restrictions. + += Will this work with my other plugins? = + +Aurora Admin only replaces the built-in WordPress admin screens it explicitly targets (Posts, Pages, Media, Users, Comments, Nav Menus, Widgets, Themes, core Settings screens, Profile, the block editor frame). Screens added by other plugins are untouched. Each replacement can also be toggled off individually in Aurora's settings if you'd rather keep the native screen for something specific. + += Where do I report a bug? = + +Use the "Report a Bug" item in the Aurora sidebar menu, or open a thread in this plugin's support forum. + += Where did File Manager, Database Explorer, and Site Backup go? = + +File Manager is now Aurora File Manager, Database Explorer is now Aurora Database Explorer, and Site Backup is now Aurora Site Backup — three separate standalone plugins, each installable with one click from Settings → Add-ons in Aurora Admin, or downloadable directly from [aurora.auroradragon.studio/file-manager](https://aurora.auroradragon.studio/file-manager), [aurora.auroradragon.studio/database-explorer](https://aurora.auroradragon.studio/database-explorer), and [aurora.auroradragon.studio/site-backup](https://aurora.auroradragon.studio/site-backup). File Manager and Database Explorer are distributed separately because WordPress.org's Plugin Directory policy doesn't allow file-management/code-editing or direct database-query functionality in a directory-listed plugin; Site Backup was split out proactively for the same class of reason (restoring a backup writes arbitrary files back into the site). + +== Screenshots == + +1. The Aurora dashboard. +2. Role Editor with capability tooltips. +3. Media Library with folders, dark mode across the admin. + +== Changelog == + += 3.6.1 = +* Fixed another round of Plugin Check findings the 3.5.1 fix didn't fully cover: `WordPress.DB.DirectDatabaseQuery.DirectQuery`/`NoCaching` are attributed by PHPCS to the *outer* `$wpdb->get_results()`/`get_row()` call line, while `PreparedSQL.NotPrepared` is attributed to whichever *inner* line the interpolated table name appears on — two different lines in a multi-line call, so a single `phpcs:ignore` comment can only ever cover one of them. Collapsed the remaining multi-line calls in Menu Creator and Admin Notices to single physical lines so one ignore comment covers both sniffs' attributed lines at once. Re-verified with an automated scan plus live REST-dispatch round-trips (menu create/list/get/delete, notice create/render/delete). + += 3.6.0 = +* Site Backup has moved to its own standalone plugin, Aurora Site Backup — install it with one click from the Settings → Add-ons screen, alongside Aurora File Manager and Aurora Database Explorer. Restoring a backup means writing arbitrary files back into the site, the same class of risk that's kept file-management functionality out of Aurora Admin proper, so it now lives in a separately-distributed companion plugin. + += 3.5.1 = +* Fixed a fresh WordPress.org Plugin Check report: the previous compliance pass's `phpcs:ignore` annotations were placed above the *opening* line of several multi-line `$wpdb->get_results()`/`get_row()`/`get_var()` calls, but PHPCS attributes violations to the exact physical line where the interpolated tokens appear — often one or more lines further down inside the call — so those suppressions were never actually taking effect. Corrected across Menu Creator, Admin Notices, Site Backup, Media Folders, Analytics, and Media Library. Also fixed a real, unrelated bug found during verification: creating a menu in Menu Creator returned "Menu not found" instead of the newly created menu, because of how the internal follow-up request object was constructed. +* Compressed files, hidden files, and non-standard markdown files flagged by Plugin Check are scanner noise from scanning the whole development repository (build zips, `.gitignore`, `.claude/`, `PROJECT_STATUS.md`) — confirmed none of these exist in the actual submission zip. + += 3.5.0 = +* Database Explorer has moved to its own standalone plugin, Aurora Database Explorer — install it with one click from the Settings → Add-ons screen, alongside Aurora File Manager. Direct database-query tooling is treated by WordPress.org's Plugin Directory review the same way as file-management functionality, so rather than remove the capability outright, it now lives in a separately-distributed companion plugin, same as File Manager did in 3.4.0. + += 3.4.0 = +* File Manager has moved to its own standalone plugin, Aurora File Manager — install it with one click from the new Settings → Add-ons screen. WordPress.org's Plugin Directory policy doesn't allow file-management/code-editing functionality in a directory-listed plugin regardless of the safeguards in place, so rather than remove the capability outright, it now lives in a separately-distributed companion plugin. + += 3.3.2 = +* Compliance pass against the official WordPress.org Plugin Check tool: fixed a readme.txt version mismatch, a missing input-sanitization call, and annotated ~230 custom-database-table query warnings with the justification the review process expects (Aurora's backup/analytics/activity-log/menu/notices/media-folders features all use their own tables, which necessarily means direct, non-core-wrapped database access). + += 3.3.1 = +* Fixed the Settings page: the category list and the settings panel now scroll independently, so picking a category from a scrolled-down spot in the list no longer leaves the panel showing stale, off-screen content above the fold. + += 3.3.0 = +* Added Modern Image Formats: automatically generates a WebP or AVIF copy of every uploaded JPEG/PNG image and serves it via a element with the original as a fallback, configurable under Settings. + += 3.2.1 = +* Security hardening: File Manager no longer allows opening or saving executable file types (PHP and similar) for a file that already exists — only creating, uploading, and renaming to those types were previously blocked. File Manager now also honors the DISALLOW_FILE_EDIT and DISALLOW_FILE_MODS constants, the same host-level lockdown WordPress core's own file-editing and update/install flows respect. + += 3.2.0 = +* Added Google Drive as a second remote storage option for Site Backup, alongside S3-compatible storage. Connect your own Google Cloud OAuth client in Settings to store backups in your own Google Drive account. + += 3.1.0 = +* Added Site Backup: full site backup (database + files) and restore-in-place, on demand or on a recurring daily/weekly/monthly schedule, stored locally or on your own S3-compatible remote storage (AWS S3, Backblaze B2, Cloudflare R2, DigitalOcean Spaces, and similar). + += 3.0.2 = +* Fixed a plugin-header validation error: Plugin URI and Author URI were identical, which the WordPress.org submission checker requires to be distinct. Plugin URI now points to the plugin's own site (aurora.auroradragon.studio); Author URI stays on the studio's site. + += 3.0.1 = +* Compliance and hardening pass ahead of the WordPress.org submission: replaced a forbidden core function in the Widgets screen, converted File Manager's file operations to use the WP_Filesystem API, added nonce/sanitization coverage to a few read paths, fixed missing translator comments, and annotated custom-table SQL queries for the plugin review process. + += 3.0.0 = +* Aurora Admin is now completely free — the entire licensing system was removed, and every previously-paid feature (Role Editor, Activity Log, Database Explorer, File Manager, Analytics, White Label, Full Admin Takeover, Media Folders) is now available to everyone. + += 2.27.0 and earlier = +* Pre-release beta versions, not distributed on WordPress.org. + +== Upgrade Notice == + += 3.0.0 = +Aurora Admin is now 100% free. If you were on an earlier beta with a license key, it's no longer needed — all features are unlocked automatically.