Skip to content

Admin Menu: add group_id + signal fields and top-level groups[] for sidebar redesign#48715

Open
chriskmnds wants to merge 2 commits into
trunkfrom
add/admin-menu-redesign-schema-fields
Open

Admin Menu: add group_id + signal fields and top-level groups[] for sidebar redesign#48715
chriskmnds wants to merge 2 commits into
trunkfrom
add/admin-menu-redesign-schema-fields

Conversation

@chriskmnds
Copy link
Copy Markdown
Contributor

Supersedes #48632 (which was opened from a fork). Reopened here from a branch on Automattic/jetpack per @jeherve's request, with the linting fixes folded in.

Part of DES-575

Overview

Extends /wpcom/v2/admin-menu with two additive per-item fields (group_id, signal) and a sibling top-level groups[] array describing the synthetic group rows the redesigned sidebar needs. Mirrors WordPress/wp-admin-sidebar v0.1.7 (the version currently vendored as the wpcom in-tree-copy at wp-content/mu-plugins/wp-admin-sidebar/).

This endpoint is the server side of the A.3 Calypso parity workstream. Pair with the Calypso PRs:

What changed

  • prepare_menu_for_response() best-effort-hydrates the classifier nav model and, when present, returns { menu, groups } instead of the legacy flat list. When the classifier isn't loaded, the response shape is byte-identical to trunk.
  • prepare_menu_item() + prepare_submenu_item() attach group_id + signal from the classifier index by menu slug. O(1) lookup; items with no nav-model match are unchanged.
  • get_item_schema() describes the new per-item fields (group_id, signal) and the optional { menu, groups } envelope.
  • Two PHPUnit tests added: legacy-shape contract when the classifier is absent; group + signal attachment + envelope when stub classifier classes are visible.
  • Jetpack changelog entry (patch / enhancement).

Screenshots

This is a backend-only schema extension. There's no Jetpack-side UI to screenshot. The visual before/after for the redesigned sidebar lives in the paired Calypso PRs (#110578, #110588) and the public plugin's wp-admin output.

Gating

The redesigned response shape is gated end-to-end on the public plugin's wp_admin_sidebar_enabled filter:

  • On non-WPCOM Jetpack installs (classifier classes not loaded), the endpoint falls back to the legacy flat shape. class_exists() guards everywhere ensure dead-code safety.
  • On WPCOM, the integration mu-plugin (wpcom-admin-sidebar-integration) wires wp_admin_sidebar_enabled to the wpcom-admin-sidebar-redesign blog sticker via WPCOM_Gating::is_enabled. No sticker → filter resolves false → Sidebar_Classifier::build_nav_model() short-circuits → endpoint emits the legacy flat shape.

So a blog without the sticker sees byte-identical behaviour to today, both in the response and on the client (Calypso treats absent groups[] as "render the legacy flat sidebar"). Removing the sticker is the rollback path, no Jetpack / Calypso deploy needed.

🟡 Reviewer-confirmable: trace Sidebar_Classifier::build_nav_model() for a stickered-off WPCOM site, confirm it returns the empty/legacy shape rather than emitting groups[] regardless.

Cross-surface persistence (layoutDelta)

The Calypso customize mode (Phase 2 PR #110588) needs to read the saved layout-delta the user persisted from wp-admin. The wp-admin side stores it in a per-user-per-blog WPCOM user attribute via WPCOM_User_Attribute_Storage.

🟡 Reviewer-actionable: confirm whether this endpoint emits the saved layoutDelta alongside menu + groups[]. If not, Calypso has no way to render the user's saved order, and customize-mode write/read parity with wp-admin breaks. If layoutDelta lives behind a separate endpoint, please link from this PR so the Calypso side knows where to read it.

The expected shape (additive to the existing response envelope):

{
  menu: AdminMenuItem[],
  groups?: AdminMenuGroup[],
  layoutDelta?: {
    overrides: Array<{
      itemId: string,
      position: { kind: 'top_level' | 'in_group', group_id?: string, index: number },
    }>,
    cleared: string[],
    version: number,
  },
}

Schema delta

Per-item (top-level + child):

{
  group_id: string | null,        // 'plugins' | null (top-level / non-grouped)
  signal: {
    count: number | null,
    numeric_badge: number | null,
    badge: string | null,
    inline_text: string | null,
    inline_icon: string | null,
    attention: boolean,           // OR of (count > 0, numeric_badge > 0, non-empty badge)
  } | null,
  itemId?: string,                // Compound `<sourceKind>:<ref>:<parent>:<slug>`
  reassignable?: boolean,         // True when the item participates in customize-mode reorder
}

Top-level (when classifier is loaded):

{
  menu: AdminMenuItem[],
  groups: Array<{
    id: string,                   // 'plugins'
    label: string,                // 'My Plugins' (i18n)
    default_expanded: boolean,
    signal: { attention: boolean, count: number },
  }>,
}

Does this pull request change what data or activity we track or use?

No. The endpoint exposes structural metadata about the admin menu the user is already authorised to see; no new tracking or logging.

Testing instructions

Without the public wp-admin-sidebar plugin loaded

/wpcom/v2/admin-menu response shape is byte-identical to trunk: same flat-array root, no group_id / signal on items, no groups[]. Existing Calypso behaviour is unchanged.

With the plugin loaded and gating enabled

  • WPCOM: set the wpcom-admin-sidebar-redesign blog sticker on a test blog: wp blog-stickers add --blog_id=<id> --sticker=wpcom-admin-sidebar-redesign --who=<user>.
  • Other hosts: any host adapter that resolves wp_admin_sidebar_enabled to true for the request user / blog.

The response root becomes { menu: [...], groups: [...] }. Each item has group_id (string or null) and signal (object or null). The groups[] array contains one { id, label, default_expanded, signal } row per synthetic group the classifier emitted.

Calypso integration check

Pair with Automattic/wp-calypso#110578 (Phase 1). Once this endpoint deploys, open /home/<site-slug> on Calypso for the stickered blog. The "My Plugins" group should render below the top-level items, in the public plugin's blue (#71aee2), with the hamburger toggle + chevron header. Items inside should show the correct signals (red number bubble, "Premium" chip, etc.) per the per-item signal payload.

PHPUnit

  • test_response_is_legacy_shape_without_classifier: legacy flat-array contract when the classifier is absent.
  • test_response_carries_group_fields_when_classifier_is_loaded: wrapped shape, per-item attachment by slug, and groups[] rows when stub classifier + signals classes are visible.
  • Existing endpoint tests (test_prepare_menu_item, test_prepare_submenu_item, test_parse_menu_item, etc.) unchanged.

Related

  • Public plugin source-of-truth: WordPress/wp-admin-sidebar v0.1.7, src/class-sidebar-classifier.php, src/class-sidebar-signals.php.
  • WPCOM integration adapter (sticker gating + storage): wp-content/mu-plugins/wpcom-admin-sidebar-integration/ in Automattic/wpcom.
  • Internal: DES-575 (A.3 Calypso parity tracker), DES-617 (schema decision on whether grouped items emit children).

chriskmnds added 2 commits May 8, 2026 09:59
…idebar redesign

Additive schema extension for `/wpcom/v2/admin-menu`. Per-item `group_id`
and `signal` fields plus a sibling top-level `groups[]` array, sourced
from the public `wp-admin-sidebar` plugin's `Sidebar_Classifier` +
`Sidebar_Signals` when loaded. The classifier hydration is gated behind
`class_exists()` so non-WPCOM Jetpack installs see no shape change.

Calypso's `MySitesSidebarUnified` view consumes these fields to render
the redesigned grouped sidebar with behaviour identical to the public
plugin's wp-admin rendering. Per-item fields use the snake_case shape
emitted by `Sidebar_Signals::map_to_nav` so the same vocabulary is
canonical end-to-end.
PHPCS: align consecutive assignments, broaden the eval phpcs:ignore to
cover both Squiz.PHP.Eval.Discouraged and MediaWiki.Usage.ForbiddenFunctions.eval
sniffs that fire on the same call.

Phan: suppress PhanUndeclaredClass{Method,Reference} for the gated
Sidebar_Classifier calls (class is provided by WPCOM's wp-admin-sidebar
mu-plugin and the runtime path is already guarded by class_exists()).
Rewrite isset(X) ? X : Y to X ?? Y to silence
PhanPluginDuplicateConditionalNullCoalescing.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the add/admin-menu-redesign-schema-fields branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/admin-menu-redesign-schema-fields

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Tests] Includes Tests labels May 12, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • 🔴 Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

@github-actions github-actions Bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label May 12, 2026
@jp-launch-control
Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-admin-menu.php 320/342 (93.57%) -0.18% 8 💔

Full summary · PHP report · JS report

If appropriate, add one of these labels to override the failing coverage check: Covered by non-unit tests Use to ignore the Code coverage requirement check when E2Es or other non-unit tests cover the code Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR I don't care about code coverage for this PR Use this label to ignore the check for insufficient code coveage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant