Core sets an explicit light background on the shared #templateside > ul
file-tree component, which nothing in native-dark.css covered - combined
with this file's dark-surface text colors, that produced light text on
a light background rather than just unstyled.
Batches everything built since the 1.0 WP.org submission reset: Login
Redirect, the Tools/Export/Import screen takeovers, Modules rebuilt as
an addon marketplace, Menu Creator's reorder fix, Activity Log
redesigned into a filterable table with Admin/User tabs, dark-theme
fixes for Site Health/Personal Data/Updates, and an opt-in Disable
Gutenberg toggle. Continues the "nothing stays native" takeover goal
and closes gaps found via live testing and the WordPress Plugin Check
tool. See CHANGELOG.md for the full per-version breakdown (1.1-1.12).
Co-Authored-By: Claude Sonnet 5 <[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]>