Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .planning/compat/PRIOR-ART-admin-menu-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,44 @@ solved — or paid for the sharp corners of — most of Maestro's hard problems.
drag-between-levels (reparenting), and per-role deny are all either Pro-gated or fragile in AME.
Maestro's own backlog (`config-presets-export-import`, reparenting v2) lines up to undercut these
for free.
- **D4 — Zero front-end footprint: one sparse, NON-AUTOLOADED row (added 2026-08-11).** The
storage-row consequence of V2, and a **key differentiator / USP** — the one Maestro claim that is
measurable by a third party (`wp option list --autoload=on`) without installing either plugin.
- **AME's row is autoloaded**, so its bytes ride in the `alloptions` bundle on every request that
boots WP — front end and logged-out included, where the data is never read. Its size grows with
the *whole* admin menu (every plugin installed adds to the stored full tree) and with every
role/user rule, not with what the user edited.
- **Where that cost actually lands** (state it precisely; the loose version invites a correction):
`wp_load_alloptions()` fetches every autoloaded row in one query and holds them in memory for
the request. The option's own `maybe_unserialize()` runs only when something calls
`get_option()` for it — so the front-end tax is the **bundle**, not that call: DB→PHP transfer,
memory, and — with a persistent object cache, where `alloptions` is a single cache object — a
per-request fetch and unserialize of the *whole* bundle, which is precisely where a fat row
hurts most. A full-page cache spares requests that never boot WP; a logged-in or otherwise
uncacheable front-end request pays in full.
- **This is acknowledged upstream, not inferred.** A wordpress.org thread reports `ws_menu_editor`
as the site's largest autoloaded row; Elsts confirms the autoload behavior and declines to flip
it because non-autoloaded "would mean an additional SQL query on every admin page", pointing to
compression instead ([support thread](https://wordpress.org/support/topic/wp_option-table-ws_menu_editor-auotload-yes/)).
Three separate size mitigations over eight years ([Pro changelog](https://adminmenueditor.com/documentation/changelog/)):
**2.5** (2017) compress-menu-config, **2.11** (2020) + zlib ("greatly decreases the amount of
data stored… but increases decompression overhead"), **2.27** (2025) "Optimize menu
configuration size" for the `ws_menu_editor_pro` entry. Three rounds ⇒ structural, not a bug.
- **Maestro's position:** one `maestro_config` row written `update_option( …, false )`
(`includes/class-config.php`), never created until first save; sparse delta so size tracks
*edits*, not installed-plugin count; hard 1 MB aggregate cap; every hook admin-gated (`Replay`
on `admin_menu`, `Admin_Bar::node()` bails on `! is_admin()`) so a front-end request reads
nothing at all. Measured: **0 extra front-end queries**; ~0.1 ms added per admin page at a
realistic 5–15 KB config, ~1 ms at the 1 MB ceiling
(`docs/performance/config-size-and-page-load.md`).
- **The trade, stated honestly:** non-autoloaded costs **1 extra admin-page query** — exactly
Elsts' objection. Maestro takes it because that query is admin-only, memoized once per request
by `Config::get()`, and zero with a persistent object cache, while public traffic — the bulk of
a live site's requests — pays nothing. AME's arrangement inverts the tax.
- **Evidence caveat:** the autoload flag comes from the author's own reply and the changelog, not
from the 1.15.1 source read (that spike recorded the storage *format*, not the autoload
argument). Confirm the `update_option` call when the free zip is next opened — the feature
sweep todo now carries that as a check.

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ The sweep is not done until each of these is enumerated and every item lands in
4. **The settings/UI surface** — what AME exposes where. Relevant because
`DECISION-settings-surface.md` locked Maestro's answer and AME is the
counter-example (a dedicated editor screen).
5. **The database-footprint features** — AME's Settings tab ships "Compress menu
configuration data" (2.5, zlib in 2.11) and "Optimize menu configuration size"
(2.27). These are *user-facing toggles*, so they are feature rows despite the
storage carve-out in Out of scope below, and they are the rows where Maestro's
**D4 differentiator** (single sparse non-autoloaded row — see
[`PRIOR-ART-admin-menu-editor.md`](../../compat/PRIOR-ART-admin-menu-editor.md)
§ Differentiate) states itself: status `deliberately-not`, because a config that
is sparse and out of `alloptions` never needs a compression toggle. Expected to
be among the strongest `have`/`deliberately-not` rows in the matrix for
competitive-positioning purposes.
**Also settle the open evidence question while the zip is open:** confirm
whether `ws_menu_editor` is written with an autoload argument at all. D4
currently rests on the author's forum reply plus the changelog, not on a source
read — grep the `update_option` call and record the answer as `source-read`.

**Completion check** (mirroring SCHEMA.md's): every file in AME's `modules/`
accounted for in at least one row; every bullet on the Pro pricing page accounted
Expand Down Expand Up @@ -117,6 +131,12 @@ The architecture comparison — apply model, hook ordering, storage format, menu
identity, submenu targeting — all answered 2026-08-01. If a feature row needs an
architectural answer, note the dependency in its Note cell and move on.

**One carve-out: the options-table footprint is in scope** (Coverage item 5). The
storage *format* is architecture and stays out, but its consequences — an
autoloaded row that every front-end request pays for, and the two Settings-tab
toggles AME ships to manage it — are user-visible and are Maestro's D4 selling
point. They earn rows.

Other prior art is also out: "Wider Admin Menu" and "Hide Admin Menu" belong to
`SPEC.md` items 9 and 10. AME-only keeps this bounded.

Expand Down
7 changes: 5 additions & 2 deletions includes/class-config.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ class Config {
* under this — five 128 KB icons plus titles/roles is ~0.65 MB. The ceiling
* exists only to refuse the pathological multi-MB payload (e.g. 200 max
* items each carrying a 128 KB icon ≈ 25 MB) that would bloat the option
* and every autoloaded read of it. An over-ceiling save is rejected whole
* rather than truncated — a partial config is worse than the prior one.
* and every admin-request read of it. (The option is stored non-autoloaded —
* see save() — so it is never part of the `alloptions` bundle; the cost the
* ceiling bounds is the per-admin-request get_option + unserialize, not a
* front-end tax.) An over-ceiling save is rejected whole rather than
* truncated — a partial config is worse than the prior one.
*
* @var int
*/
Expand Down
26 changes: 17 additions & 9 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
=== Maestro: The Inline Admin Menu Editor ===
Contributors: dpknauss
Donate link: https://github.com/sponsors/dknauss
Tags: admin menu, admin menu editor, menu editor, hide menu items, menu icons
Tags: admin menu, menu editor, hide menu items, rename menu items, menu icons
Requires at least: 6.4
Tested up to: 7.0
Stable tag: 1.5.1
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Rename, reorder, change icons, and hide WordPress admin menu items per user role — an inline admin menu editor you drive right on the menu itself.
Hide admin menu items per user role, rename them, reorder them, swap their icons — an inline admin menu editor you drive right on the menu itself.

== Description ==

**Maestro lets you orchestrate the appearance of the WordPress admin menu.**
**Maestro lets you orchestrate the appearance of the WordPress admin menu — rename admin menu items, reorder them, change their icons, and hide admin menu items from the roles and people who don't need them.**

Instead of a separate settings screen, Maestro turns the admin menu into something you edit *in place* — right where it lives. Toggle **Edit Menu** from the admin bar, and the menu becomes editable. Click a menu item to rename it, hide it from selected user roles, or change its icon. Drag submenu items and whole menu groups to reorder them.
Every WordPress install accumulates menu clutter. A dozen plugins each claim a top-level slot, submenus sit in an order nobody chose, and clients meet a dashboard full of tools that aren't theirs. Maestro is how you customize the admin menu back into shape: **declutter** it for a client site, **rename** cryptic plugin labels into the words your team actually uses, **reorder** the admin menu so what you touch daily is at the top, and **hide admin menu items per user role** — or from one named person — so everyone sees only their own work.

Instead of a separate settings screen, Maestro turns the admin menu into something you edit *in place* — right where it lives. Toggle **Edit Menu** from the admin bar, and the menu becomes editable. Click a menu item to rename it, hide it from selected user roles, or change its icon. Drag submenu items and whole menu groups to reorder them. Nothing to configure first, and nothing to learn: the menu you are editing *is* the menu you are looking at.

And it stays out of the way. Maestro adds **no autoloaded options** and does no work at all on the front end, so a menu you tidied for the dashboard costs your visitors nothing (see **Performance & footprint** below).

**Try Maestro right here.** Launch a demo in [WordPress Playground](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Maestro/main/playground/blueprint-hosted.json) — it boots a throwaway site with the plugin active in edit mode, plus User Switching and test users (editor, author, contributor, subscriber; password `password`) so you can try per-role visibility by switching to another user's account.

Expand Down Expand Up @@ -128,15 +132,19 @@ their current parent.

== Performance & footprint ==

**Unlike other admin menu editors, Maestro won't hurt your site's performance. It's small enough that there is nothing to compress, optimize, or tune.**

Maestro is built to stay out of the way:

* **Zero extra database queries on the front end.** Every hook is admin-only, so the plugin is completely inert for public page loads and logged-out visitors.
* **One extra query on an admin page** — a single, *non-autoloaded* option (`maestro_config`), read once per request and cached. With a persistent object cache (Redis / Memcached) that drops to zero.
* **Nothing added to `alloptions`.** Because the option is not autoloaded, it adds no weight to the bundle WordPress loads on every request.
* **Nothing added to `alloptions` — the one that matters.** WordPress loads every *autoloaded* option into memory on every request that boots it, including front-end pages served to logged-out visitors. A menu configuration is admin-only data, so an autoloaded one is a tax on traffic that will never read it — and a bloated autoloaded bundle is a classic cause of a sluggish site. Maestro's option is explicitly non-autoloaded. **Check it on your own site:** `wp option list --autoload=on` will not list `maestro_config`.
* **Zero extra database queries on the front end.** Not merely "light" — inert. Every hook is admin-gated, so a public page load reads nothing at all.
* **One extra query on an admin page** — a single, *non-autoloaded* option (`maestro_config`), read once per request and cached, no matter how many parts of the plugin ask for it. With a persistent object cache (Redis / Memcached) that drops to zero. This is a deliberate trade: one query where the data is actually used, so that public traffic — the bulk of what a live site serves — pays nothing.
* **Storage tracks your edits, not your plugin count.** Maestro stores a sparse delta: three renamed items are three renamed items, whether the site runs five plugins or fifty. A typical configuration is 5–15 KB, with a hard 1 MB ceiling.
* **Minimal storage.** One `wp_options` row, created only when you first save a change — a fresh install stores nothing. No custom tables, no post or user meta, no transients, no cron jobs. Uninstalling deletes that single row.
* **Small install** — roughly a 115 KB download. Menu changes are applied in memory during the `admin_menu` pass, not through extra queries.
* **Measured, not asserted.** At a typical configuration size Maestro adds roughly **0.1 ms** to an admin page load; even a pathological config at the 1 MB ceiling adds about **1 ms**. Menu changes are applied in memory during the `admin_menu` pass, not through extra queries. Method and full numbers: [config size vs. page-load cost](https://github.com/dknauss/Maestro/blob/main/docs/performance/config-size-and-page-load.md).
* **Small install** — roughly a 115 KB download.

(Figures are a v1.4.1 snapshot.)
(Size figures are a v1.4.1 snapshot; timings were measured 2026-08-03 on WordPress 7.0 / PHP 8.3.)

== Known limits / deferred to v2 ==

Expand Down
Loading