Extend Settings > Login (beyond the existing style toggle + logo) toward
Loginfy parity: background image or color, form-panel background, button/
focus-accent color, and a custom login CSS field — all dependent on
"Style login page" and all falling back to the original fixed dark theme
when unset. LoginStyle.php sanitizes colors via sanitize_hex_color(),
esc_url()s the background image, and appends custom CSS (</style> stripped).
Verified on wp-login.php.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
New Settings > Code group (Custom CSS & JS + Header & footer scripts) driven
by admin/src/Code/CodeInjection.php:
- Admin CSS → <style> in the admin <head> (</style> stripped to prevent breakout)
- Admin JS → <script> in the admin footer (</script> neutralized)
- Header scripts → printed verbatim in the front-end <head>
- Footer scripts → printed verbatim before the front-end </body>
Header/footer scripts are raw admin-authored markup by design (analytics,
meta, etc.), settable only by manage_options users on the settings page.
SettingsField gains a `mono` flag for monospace textareas (no CodeMirror
dependency). All four injection points verified on PHP 8.5.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
New Settings > Security & performance group (Hardening + Performance) with
toggles wired by admin/src/Security/Security.php — each gated on its own
setting, adding/removing core hooks so anything left off behaves exactly like
stock WordPress:
- Disable XML-RPC (xmlrpc_enabled false + drop X-Pingback header)
- Disable comments site-wide (close everywhere, strip post-type support,
remove the Comments menu/dashboard-widget/toolbar node)
- Clean up <head> (generator, RSD, WLW manifest, shortlink)
- Disable emoji scripts/styles + the s.w.org dns-prefetch
- Disable oEmbeds (discovery links, host js, embed REST route, wp-embed) —
discovery links are removed at whatever priority core hooks them (loops,
since they can be registered at more than one)
- Heartbeat API: default / slow (60s) / disabled
New setting keys need no schema change (Settings::merge_on_save +
additionalProperties). Every toggle verified at the hook level on PHP 8.5.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Full-screen onboarding at admin.php?page=aurora-admin-setup: Welcome →
Appearance (theme + font) → Branding (logo/favicon/rename) → Features
(replacement-screen toggles) → Done. Reuses SettingsField for every control
and applyLiveTheme for instant preview; finish/skip saves via wp/v2/settings
and marks completion.
- admin/src/Pages/SetupWizard.php: hidden submenu page, disables the shell on
its own page (aurora_admin_shell_enabled filter) + hides native chrome,
register_activation_hook sets a one-time redirect flag, admin_init redirects
once, and a POST /aurora-admin/v1/setup/complete route marks it done.
- app/src/pages/setup-wizard/SetupWizard.vue + entries/setup-wizard.js + vite
input.
- Wired into aurora-admin.php + AuroraAdmin.php.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add a small left indent to .settings__list so each group's categories read
as a nested submenu rather than sitting flush with the group header.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Consolidate ~140 scattered hardcoded border-radius values (and the old
--aurora-radius/--aurora-radius-lg vars) onto one four-step scale defined in
shell-frame.css:
--aurora-radius-sm 10px (chips, small/icon controls; was 5-8px)
--aurora-radius-md 14px (buttons, inputs, search, list rows; was 9-14px)
--aurora-radius-lg 20px (cards, panels, larger buttons; was 15-20px)
--aurora-radius-xl 28px (page frames: content card, dashboard, sidebar,
editor; was the 24px --aurora-radius-lg)
Everything is one notch rounder, and the whole UI's roundness is now tunable
from four lines instead of 35 files.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Strip the whole window metaphor as UI baggage: the traffic-light dots
injected at the top of every page, the minimize taskbar, and the
minimize/maximize state and all their CSS. windowChrome.js and taskbar.js
are gone; the only structural DOM the shell still does — wrapping the
takeover Dashboard in .aurora-dashboard-frame and reparenting its notices
into the card — moved to a focused dashboardFrame.js (initDashboardFrame()).
SiteShell.vue drops the taskbar rendering/state; shell-frame.css drops the
.aurora-winbar*/.aurora-taskbar*/minimized/maximized rules and the
--aurora-taskbar-h / --aurora-editor-winbar-h vars, and zeroes the editor
and theme-install frame offsets that reserved a top strip for the dots.
shell.js 16.4->13.4 kB. The editor "back to list" crumb lived in the bar
and was removed with it (Gutenberg's own W-logo still navigates back).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
@codemirror/* (8 language packages) and codemirror were declared but
imported nowhere in src — leftovers from the removed File Manager and
Database Explorer. Dropped all nine; removes 30 packages from the install
(node_modules ~44 MB -> ~39 MB). Not bundled before (unused), so the built
output is unchanged. If the future custom CSS/JS editor needs an in-browser
code editor, add back the specific packages it uses at that point.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Pin `vue` to a named `vendor-vue` chunk (manualChunks) so its hash stays
stable across app-code changes — returning users keep it cached across
plugin releases instead of re-downloading ~31 kB gzip each update. Also
replaces the misleadingly-named `_plugin-vue_export-helper` shared chunk.
- Gate sourcemap emission on AURORA_SOURCEMAP (default on for the local
hot-patch dev loop; the distribution build sets it to false). Cuts a
from-scratch dist build's app/dist from ~1.7 MB to ~502 kB by dropping
27 .map files that ship no value to end users.
- Refresh the stale header comment (was "one entry in this first slice").
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Restructure the flat settingsCategories list into five top-level groups
(General, Appearance, Screens, Productivity, Add-ons), each a collapsible
nav section with persisted open/closed state. Consolidate the six
single-toggle modern_* categories (posts/pages/media/users/comments/
plugins) into one "Content tables" screen. Search now matches on group +
category + subtitle and hides empty groups. Field definitions, save flow,
and setting keys are unchanged.
settingsConfig.js exports settingsGroups plus a flattened settingsCategories
for default-seeding and deep-link lookups.
(package-lock.json: version field synced 2.16.0 -> 3.1.0 to match package.json.)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Reworded "What this project is" to describe Aurora on its own terms and
dropped the stale uixpress/ folder archaeology from the Repo section.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Machine-sync snapshot: the working tree carried the full 3.0.0-3.6.1 arc
(licensing/FileManager/DatabaseExplorer removal, all new replacement screens
and REST controllers) that had not been committed on this machine. Captured
here as a safety baseline before starting the Adminify-parity revamp.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Unlike Posts/Pages/Media/Users/Comments, Plugins only ever had its
sidebar link rewritten (MenuSerializer.php) — there was no
redirect_native_pages() case for direct visits to plugins.php itself.
WordPress's own post-activate/post-install redirect
(wp_redirect(self_admin_url('plugins.php?activate=true'))) is exactly
that: a direct visit with no ?page= param, landing on the true native
page until the sidebar link was clicked again.
Added the missing case, gated by modern_plugins like the others,
redirecting to plugins.php?page=aurora-admin-plugins to match the URL
the sidebar link itself already uses.
Verified live by visiting plugins.php?activate=true directly (the
exact URL WP's own redirect produces) — now lands on the Aurora page
correctly, confirmed with FileBird Lite showing Active in the list.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Native form fields (title inputs, textareas, selects) on screens that
don't use the block editor — most visibly Edit Media's title field —
were showing stark white, breaking the dark theme. WP core styles some
fields via a 2-ID selector (#titlediv #title { background: #fff }),
which beats native-dark.css's existing form-field rule regardless of
class count, same specificity trap as an earlier block-editor
background bug. Added !important to the whole form-field rule block —
safe everywhere, no legitimate case for a native admin field to stay
white.
Verified this one rule fixes Edit Media, Edit Post (classic fields),
and Comment edit simultaneously; Add User was already clean. The
WYSIWYG editor body staying white is a separate, deliberate decision
(matches the block editor's own canvas) and wasn't touched.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
New browse/edit interface for the WordPress install's own files, built
using the installed "WP File Manager" plugin (elFinder-based) as a
functional reference rather than embedding it. Own REST controller
(FileManagerData.php) + Vue page, same pattern as every other sub-app.
Security is the whole point here (highest-risk surface in the plugin —
arbitrary filesystem read/write):
- Root is ABSPATH, manage_options-gated throughout.
- Every client path is resolved via realpath() and checked for root
containment against the *resolved* path, not string-matched against
the raw input — catches symlink tricks and encoded traversal that a
naive "../" check would miss.
- Uploads/new files/renames reject a blocklist of server-executable
extensions (.php, .cgi, .sh, etc.) — the single most important
control, since uploading a webshell is the classic exploit path for
this class of feature.
- Deliberately not built: zip/unzip (zip-slip vulnerability class),
chmod/permissions editing, cross-directory move/copy.
Gated as a paid feature (riskier than Database Explorer, which is
already paid) — a judgment call flagged to the user, not something they
specified.
Also fixed a real bug found while wiring this up: SubApps.php's
page-level lock doesn't stop someone with manage_options from calling
the REST endpoints directly, bypassing the license check entirely.
File Manager's REST permission callbacks now also check
License::is_feature_available(). The same gap exists in Database
Explorer, Role Editor, and Activity Log's REST controllers and is
flagged as a follow-up task, not fixed here (out of scope for what was
asked, affects three unrelated features).
Verified live via direct REST calls: path traversal blocked (404),
blocked extensions rejected (400), root deletion blocked (400), and a
full create/write/read/rename/delete round trip succeeded cleanly.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Completes the "skinned vs. replaced" conversion started with Posts —
every native list-table screen the user asked about now has a genuine
custom Vue page behind it instead of dark-themed CSS over the native
markup. All three follow the same pattern as Posts: own REST controller
in admin/src/Rest/, own Vue page matching the Comments layout, native
screen redirected away (direct visits too, not just the sidebar link),
gated by its own Settings toggle defaulting to on.
- Pages (PagesData.php + Pages.vue): same as Posts, parent page shown
instead of categories. edit.php?post_type=page redirects; other post
types untouched.
- Media Library (MediaData.php + Media.vue): thumbnail grid with type
filters (Images/Audio/Video/Documents/Unattached). Replaces the
browse/library experience only — media-new.php (the actual upload
screen) is untouched, same reasoning as leaving the block editor
alone for Posts/Pages.
- Users (UsersData.php + Users.vue): filterable by role. Deleting a
user always reassigns their content to whoever performs the deletion
rather than exposing WP core's reassign-or-delete-everything choice
as a one-click action — deliberately simplified to avoid a surprising,
highly destructive default. user-new.php untouched.
Verified live: Media's grid renders real thumbnails/dimensions/file
sizes with working filters and search; Users shows real accounts with
role filters and correctly hides delete for the current user; both
redirect correctly from their native URLs.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Posts was previously just dark-themed skinning over the native
edit.php list table, unlike Comments/Plugins which are genuine
replacements. Built the same way: new PostsData.php REST controller
(list with status/search filters matching native tabs, trash, restore,
permanent delete) and a Vue page matching the Comments layout.
- SubApps.php registers it as aurora-admin-posts, parented under
edit.php (same pattern as Plugins under plugins.php).
- redirect_native_pages() redirects direct edit.php visits (typed URL,
not just the sidebar link) to the Aurora page — gated to the default
post type only, so Pages and other custom post types are untouched.
- MenuSerializer rewrites the sidebar's Posts/All Posts links the same
way Plugins/Comments already were.
- Gated by Settings > Posts' "Modern posts table" toggle, re-added now
that it has a real implementation (it was removed a few commits ago
for describing a feature that didn't exist).
- Fixed modern_plugins/modern_comments/modern_posts all defaulting to
visually "on" in the Settings UI to match their actual PHP default.
Verified live: trash/restore/status filters/search all work correctly,
edit.php redirects to the Aurora page, edit.php?post_type=page (Pages)
correctly does not.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
admin_notices fires everywhere, but prints inside #wpbody, which
DashboardTakeover hides entirely on the Dashboard (to hide the *native*
dashboard, not ours) — notices went down with it as collateral damage.
Notices::render_for_dashboard() now renders directly inside the visible
dashboard frame instead, called from DashboardTakeover::render_mount();
the normal admin_notices path bails on the Dashboard so it isn't
rendered twice.
Second, independent bug found along the way: wp-admin/js/common.js
unconditionally relocates every .notice element on the page to right
after the page's <h1>, regardless of where it was placed server-side —
without opting out, it would've silently moved our notice right back
into the hidden #wpbody. Used core's own documented `below-h2` class to
opt out, only for the dashboard render path.
Verified live: notice now shows correctly inside the dashboard frame
with proper dark styling, and dismisses correctly.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
.aurora-dashboard-frame never got the height-cap + internal-scroll
treatment #wpbody-content got in an earlier session (it bypasses
#wpbody-content entirely, using its own element) — only the
taskbar-present variant applied to it. Combined with html/body being
locked to overflow:hidden in that same earlier fix, dashboard content
below ~1500px became completely unreachable: no internal scroll, and
no document scroll left to fall back on. Mirrored the same
max-height/overflow-y/overflow-anchor treatment onto the dashboard
frame. Verified live — Server Health, Media Analytics, and the rest of
the dashboard scroll into view correctly now.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Custom dashboard, Modern plugins page, and Modern comments page
toggles previously had no effect at all — their respective takeovers/
redirects (DashboardTakeover, SubApps' Plugins/Comments handling,
MenuSerializer's link rewrites) ran unconditionally regardless of the
setting. All three now default to their previous always-on behavior
but can actually be turned off.
- Menu search had zero implementation. Sidebar.vue now shows a real
search box (gated on the setting) that filters both the WP-native menu
and the Aurora nav section by title, auto-expanding matching sections.
- Removed "Modern posts table" and "Modern users page" toggles (and
their now-empty Posts/Users settings categories) — both described a
custom management page that was never built. A checkbox with nothing
behind it is worse than no checkbox.
Verified all four live: dashboard/plugins/comments toggles correctly
flip between the Aurora and native experience and back; menu search
filters correctly and clears back to the full menu.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Aurora's branded nav section had its own independent expand/collapse
state, so it stayed open regardless of which native menu section was
expanded — the one exception to the single-open accordion. Unified
under one openId ref (a sentinel value for Aurora alongside real
native-menu item ids) so expanding either collapses the other.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
The toggle existed in the UI with no implementation behind it, so
uploads were rejected regardless of the setting. New SvgUploads class:
- Allowlists the SVG mime type and fixes WP's real-mime sniff, which
otherwise nulls out the file type for SVGs specifically even after
the mime allowlist is updated.
- Populates width/height metadata (parsed from the SVG's own
viewBox/width/height) — without this, wp_get_missing_image_subsizes()
throws undefined-array-key warnings that can corrupt the upload
response's JSON on environments with warnings displayed inline.
- Basic sanitization on upload (strips <script> tags, inline event
handlers, javascript: URIs).
Verified live via the REST media endpoint: clean upload with correct
dimensions, and a malicious test SVG had its script/handlers stripped
while staying valid markup.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
"Style login page" and "Login logo" existed in the Settings UI with no
implementation behind them at all. New LoginStyle class hooks
login_enqueue_scripts to apply a dark theme (background, form card,
inputs, button) and swap in the configured logo, linked to the site's
home URL instead of wordpress.org.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
wp_enqueue_media() was never called on the Settings page, so wp.media
was undefined client-side and every image field (Logo, Dark mode logo,
Login logo, Admin favicon) silently fell back to a plain URL prompt
instead of the WordPress media library. Also relabeled the picker
button ("Choose from media library" instead of "{label} url") so it
reads as a picker, not a URL field.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Covers this session's work: free/paid feature gating, real
auroraplugins.com license validation, and file-integrity tamper
protection for the license gate.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- New Integrity class checksums the files that implement/enforce the
free/paid split (SubApps, Analytics, AnalyticsData, WhiteLabel, Shell,
License itself, and the two bootstrap files) against a manifest
generated at zip-build time. No manifest present (a dev checkout) is
never treated as tampered.
- License::is_feature_available() checks Integrity::is_tampered() before
checking the actual license, so a distributed copy with the check
stripped/commented out re-locks every paid feature even with an
otherwise-valid license, rather than the plugin trusting whatever code
happens to still be there.
- bin/build-integrity-manifest.php generates the manifest against a
staged zip-build copy (gitignored build artifact, same pattern as
app/dist) — now a required step in the zip-build workflow.
- Verified live: untampered+unlicensed stays locked, untampered+licensed
unlocks, one tampered file re-locks regardless of license status
(tested via a temporary mu-plugin faking an active license, kept
outside any protected file so it didn't itself trip the check).
This raises the bar against the realistic low-effort case (finding and
deleting/inverting the one license-check line) but can't stop someone who
rewrites a file's logic to never call the gate, or who edits this
integrity check itself — an inherent limit of protection living in plain,
editable PHP.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- License.php now calls the aurora-licensing plugin's REST API
(/wp-json/aurora-licensing/v1/validate|activate|deactivate) instead of
treating any non-empty license_key as active. Result is cached in the
aurora_admin_license_status option for 12 hours; is_active() and
is_feature_available() read the cache instead of hitting the network on
every admin page load.
- Hooks update_option_aurora_admin_settings to activate/deactivate
immediately when the license_key setting actually changes, rather than
waiting out the cache. Instantiated in AuroraAdmin.php so that hook
registers.
- Settings page now surfaces the real status (active/invalid/unreachable,
with the server's own message) as a status line under the License key
field, instead of a field that silently does nothing.
- Verified live against the real server: a fake test key correctly came
back locked with the server's own "License key not found." message.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Analytics, White Label, remote site switcher are paid)
- New License class is the single gate every paid feature checks —
today it's a placeholder (any non-empty license_key counts as active)
since there's no license server yet, but every gated feature already
funnels through it so swapping in real remote validation later won't
touch anything else.
- Role Editor, Activity Log, and Database Explorer stay registered/
capability-checked as before, but render an UpgradeNotice screen
instead of the real feature when unlicensed (and skip loading the
real JS bundle/REST data). Menu Creator, Admin Notices, Comments,
and Plugins stay free.
- Analytics' tracking hooks and REST endpoint, and White Label's
favicon/rename/text-replace hooks, simply don't register without a
license. Settings fields for both stay visible/editable either way.
- Remote site switcher gated alongside its existing capability check.
- Sidebar shows a small lock badge on locked Aurora nav items; the
Dashboard's Analytics tab shows the same upgrade prompt when locked.
- Fixed an unrelated bug surfaced while testing Role Editor: RolesData's
REST callback called get_editable_roles() without loading
wp-admin/includes/user.php first, which REST requests don't get for
free (only real wp-admin page loads do) — 500'd every time.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Apply the taskbar's max-height/overflow-y:auto treatment to
#wpbody-content unconditionally, so tall native/Aurora pages (Add
Plugins, Add User, Profile, Fonts, file editors, Settings, Activity Log,
Database Explorer, Comments) scroll internally within their frame
instead of growing past the viewport and scrolling the whole document.
- Fix a Chrome scroll-anchoring bug this surfaced on Add Plugins (page
loaded scrolled ~1700px into content instead of at the top) via
overflow-anchor: none.
- Fix a phantom document-level scrollbar with dead space below the frame
by locking html/body's own overflow, since the sidebar/toolbar are fixed
and content is only ever meant to scroll internally.
- Make the sidebar's native-menu sections a single-open accordion:
expanding one now collapses whichever else was open.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
- Root-cause fix for "Sorry, you are not allowed to access this page" on
Menu Creator/Activity Log/Role Editor: remove_submenu_page() was
corrupting WP core's user_can_access_admin_page() capability lookup.
Sub-apps now stay registered in $submenu; MenuSerializer filters them
out of the sidebar instead.
- Add a 6th sub-app, Comments, with a redirect from native edit-comments.php.
- Extend the window-chrome/taskbar framing to the Site Editor
(site-editor.php), including a fix for a CSS position:fixed
over-constraint bug that let its frame run past the viewport.
- Rewrite the taskbar from a single sessionStorage slot to a list so
multiple minimized windows are each independently restorable.
- Extend native-dark.css coverage to the block editor's own chrome.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Documents this session's work: the new fixed-preset theme system
(gradients, the recurring "independently-painted gradient" seam bug
pattern), the macOS-style window chrome + taskbar feature, extended
native-page dark styling coverage, and the still-open sub-app permissions
bug.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Replaces the old light/dark toggle with 10 fixed color themes (plus
Black & Grey and White) that drive a coordinated gradient palette across
the whole admin UI, a Google Fonts picker, and a native-page dark-mode
stylesheet that now covers modals and plugin/theme card grids. Fixes
several background/gradient seams where the sidebar, toolbar, and content
frame were each painting their own independent copy of the page gradient
instead of sharing one continuous plane.
Also adds a macOS-style traffic-light title bar to every page (close,
minimize, maximize) and a persistent bottom taskbar so a minimized page
can be restored from anywhere, plus a Plugins management page.
Co-Authored-By: Claude Sonnet 5 <[email protected]>