Skip to content

Repository files navigation

Admin Menu Organizer

Groups WordPress admin menu items into named, collapsible categories inside the native sidebar. Sorts what it recognises automatically, and lets you rearrange everything else by drag and drop.

CI  License: GPLv2 or later  ·  Requires WordPress 6.4+  ·  Requires PHP 7.4+


Installation

Not yet on the WordPress.org directory, so install it from a zip for now.

From a release zip

  1. Download the latest admin-menu-organizer.<version>.zip from Releases.
  2. In your dashboard go to Plugins → Add New → Upload Plugin.
  3. Choose the zip, click Install Now, then Activate.
  4. Your sidebar is grouped immediately, using the automatic rules. Nothing to configure.
  5. To rearrange anything, go to Settings → Menu Organizer.

Building the zip yourself

Requires PHP 7.4+ and Composer.

git clone https://github.com/submoro/admin-menu-organizer.git
cd admin-menu-organizer
composer install
composer run build

That runs the full gate — linting, tests, security audit, readme validation — then writes build/admin-menu-organizer.<version>.zip. Upload that as above.

Installing directly into a site

If you have filesystem access, clone straight into your plugins directory. The repository folder name must be admin-menu-organizer, because WordPress derives the text domain from it:

cd wp-content/plugins
git clone https://github.com/submoro/admin-menu-organizer.git

Then activate it from the Plugins screen. No composer install is needed to run the plugin — it has no runtime dependencies. Composer is only for the development tooling.

With WP-CLI

wp plugin install /path/to/admin-menu-organizer.1.0.0.zip --activate

Requirements

WordPress 6.4 or newer
PHP 7.4 or newer
Multisite Works per-site. The network admin menu is deliberately left untouched.

Uninstalling

Deactivating restores the stock sidebar exactly and keeps your saved arrangement, so reactivating brings it back. Deleting the plugin removes every option and user meta key it created — there is no residue.

The problem

A production site accumulates thirty to sixty plugins, and every one of them adds a top-level item to wp-admin's sidebar. The result is a flat, unsorted list several screens long, with an SEO plugin next to a mail-delivery plugin next to a firewall. There is no grouping and no way to impose order without editing code.

What this does

It reorders and decorates the existing menu. It never rebuilds it, never removes an item, and never touches a capability.

  • Groups top-level items into categories: Content, Commerce, Design, SEO, Security, Performance, Users, Integrations, Tools.
  • Recognises plugins on sight and files them correctly — including plugins it has never heard of, see Detection.
  • Full drag-and-drop override, with a keyboard equivalent for every drag.
  • Per-user open/closed memory; the group containing the current page always opens.
  • Collapsed groups show an aggregated update-count badge.
  • Site-wide default, optional per-role layouts, optional per-user personalisation.

What it deliberately does not do

  • Never hides an item. Anything unrecognised goes to an always-visible Other group. Nothing becomes unreachable in any configuration.
  • Never modifies index 1 of a menu item, so it cannot grant or revoke access.
  • Does not restyle the admin beyond the menu.
  • Does not touch the network admin menu on multisite; that screen is left alone.
  • Makes zero outbound HTTP requests. No telemetry, no analytics, no calling home. This is enforced by the test suite, not merely promised.

Detection

The interesting part. Rather than a lookup table that goes stale, detection is an eight-layer cascade, each layer more general than the last:

Layer Signal
1 Explicit human override in the saved layout
2 Core slug map (edit.php, themes.php, …)
3 Curated table of 343 known plugin menu slugs
4 Post-type defaulting — edit.php?post_type=X, with unknown types → Content
5 Vendor prefixes (wpseo, wc-, elementor, yith_, tribe_, …)
6 Namespaced capabilities (manage_woocommerce, wpseo_manage_options, …)
7 Weighted keyword scoring over title and slug, with a confidence floor
8 Dashicon as a tiebreak (dashicons-cart, dashicons-shield, …)

Measured against 40 real plugins deliberately excluded from the table: 40 / 40 correct. The highest-value rule is layer 4 — an unrecognised custom post type is content, which files every CPT on every site without naming any.

When signals tie or score too low, it declines rather than guesses, and the item lands in the always-visible Other group.

Extend it without forking:

add_filter( 'amorg_known_slugs',          function ( $map ) { $map['my-plugin'] = 'commerce'; return $map; } );
add_filter( 'amorg_category_definitions', function ( $groups ) { /* add your own */ return $groups; } );
add_filter( 'amorg_resolve_group',        function ( $group_id, $item ) { return $group_id; }, 10, 2 );
add_filter( 'amorg_resolved_layout',      function ( $layout ) { return $layout; } );

If something goes wrong

Two escape hatches, both of which always work and neither of which discards your saved arrangement:

?amorg=off                          # disables it for one page load
define( 'AMORG_DISABLE', true );    # in wp-config.php, disables it entirely

How it works

WordPress builds $GLOBALS['menu'] during admin_menu and renders it in wp-admin/menu-header.php. Every capability check, update bubble, current highlight and third-party integration depends on that pipeline staying intact, so this plugin leaves it intact.

Hook Purpose
custom_menu_order Unlock reordering
menu_order Return every slug, deduped, grouped contiguously
add_menu_classes Decorate items; inject group header rows
admin_body_class Emit collapsed state, server-side

Ordering, grouping and collapsed state are all server-rendered, so there is no flash of an ungrouped menu. JavaScript only fills in the header's button, into a row whose height CSS already reserves — so no layout shift. With JavaScript off, every group renders expanded and fully usable.

Design notes, and the four places WordPress core contradicted the original specification, are in docs/core-notes.md and docs/decisions.md.

Development

composer install
composer run test          # unit suite, needs no database
composer run lint          # phpcs: WordPress, -Extra, -Docs, PHPCompatibilityWP
composer run audit         # security audit against the project's own rules
composer run build         # full gate, then produce the release zip

The test suite is split. tests/unit/ needs nothing but PHP and runs anywhere; tests/integration/ needs WordPress and a database and runs in CI. That split forces the detector, sanitiser, reorderer and migration chain to be pure functions of their arguments, which is better structure regardless.

A caveat worth knowing: phpcs does not prove PHP 7.4 compatibility here. The current stable PHPCompatibility release predates PHP 8.0 and cannot see PHP 8 syntax — verified with a canary using ?-> and match that it waved straight through. The binding check is the syntax-php74 CI job, which parses every shipped file with a real PHP 7.4 binary.

Verification

CI runs 11 jobs, all green:

Plugin Check passes all five categories, run against the built zip rather than the repo
Integration suite 29 tests on PHP 7.4 / 8.1 / 8.3 against both WordPress 6.4 and current stable
Unit suite 295 tests, 2995 assertions, on PHP 7.4 / 8.1 / 8.3
PHP 7.4 syntax every shipped file parsed by a real 7.4 binary
Coding standards WordPress, -Extra, -Docs, PHPCompatibilityWP
No outbound requests source scan, plus a pre_http_request tripwire in the suite

The $menu internals, the menu_order semantics, the finished accordion render and the compiled .mo are each proven by executing real WordPress core code rather than a reimplementation of it — see docs/recon/.

What is not verified: anything requiring a rendered page. The nine colour schemes, RTL, the responsive breakpoints, keyboard navigation and a screen-reader pass have not been looked at in a browser. Honest status in docs/decisions.md.

Releasing

See docs/release.md for the pre-submission gate, the zip build and the WordPress.org SVN layout.

License

GPLv2 or later. See LICENSE.

Icons and banners are original artwork generated by bin/build-assets.php. No third-party assets, fonts or libraries are bundled; the drag-and-drop editor uses jQuery UI Sortable, which ships with WordPress.

About

Groups WordPress admin menu items into named, collapsible categories inside the native sidebar. Auto-sorts known plugins, with full drag-and-drop control.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages