Summary
The desktop_mode_mode_enabled filter is the documented surface for gating which users get Desktop Mode. Today it is enforced at three call sites (the AJAX save endpoint, the /desktop-mode/ portal, and now the admin-bar toggle from #98) but NOT in the central desktop_mode_is_enabled() helper, which only reads user meta.
This means a user who set the user meta in the past and then had the filter flipped against them will still register as "enabled" everywhere desktop_mode_is_enabled() is consulted as a render-time gate. The filter is leaky.
Evidence
includes/helpers.php:17-23 (current implementation):
function desktop_mode_is_enabled( $user_id = 0 ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
return '1' === (string) get_user_meta( $user_id, 'desktop_mode_mode', true );
}
The filter is never consulted. The doc example at docs/examples/gate-by-role.md previously claimed it WAS, that doc was corrected to match code in #98, but the original wording is probably the intended contract.
Filter enforcement today (only here):
Proposed change
Make desktop_mode_is_enabled() AND on the meta AND on apply_filters( 'desktop_mode_mode_enabled', true, $user_id ). After the change:
function desktop_mode_is_enabled( $user_id = 0 ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
if ( '1' !== (string) get_user_meta( $user_id, 'desktop_mode_mode', true ) ) {
return false;
}
return (bool) apply_filters( 'desktop_mode_mode_enabled', true, $user_id );
}
Risk and scope
This is a behavior change at every call site of desktop_mode_is_enabled(), used as a render-time gate in many places (chromeless rendering, admin-bar, payload generation, REST permission checks, etc.). Most call sites should benefit from the tighter gate. Risks worth thinking through before shipping:
- A user with the meta set whose filter newly returns false will be kicked back to classic admin on next page load. That is the intended behavior of the filter, but worth documenting prominently.
- Tests that bypass the filter (set the meta directly, then assert enabled) will need updating to also stub the filter or accept the new contract.
Suggested fix
- Update
desktop_mode_is_enabled() per above.
- Add a unit test confirming the filter overrides positive meta.
- Audit existing callers for any that might be surprised; document the change in
docs/hooks-reference.md and docs/examples/gate-by-role.md.
- CHANGELOG entry, this is a contract-tightening, technically a behavior change.
Related
Follow-up to #98.
Summary
The
desktop_mode_mode_enabledfilter is the documented surface for gating which users get Desktop Mode. Today it is enforced at three call sites (the AJAX save endpoint, the/desktop-mode/portal, and now the admin-bar toggle from #98) but NOT in the centraldesktop_mode_is_enabled()helper, which only reads user meta.This means a user who set the user meta in the past and then had the filter flipped against them will still register as "enabled" everywhere
desktop_mode_is_enabled()is consulted as a render-time gate. The filter is leaky.Evidence
includes/helpers.php:17-23(current implementation):The filter is never consulted. The doc example at
docs/examples/gate-by-role.mdpreviously claimed it WAS, that doc was corrected to match code in #98, but the original wording is probably the intended contract.Filter enforcement today (only here):
includes/ajax.php:23, 37(save-desktop-mode AJAX)includes/portal.php:74(/desktop-mode/ portal entry)includes/admin-bar.phpafter First-time admins have no on-screen path to discover Desktop Mode #98 (admin-bar toggle render gate)Proposed change
Make
desktop_mode_is_enabled()AND on the meta AND onapply_filters( 'desktop_mode_mode_enabled', true, $user_id ). After the change:Risk and scope
This is a behavior change at every call site of
desktop_mode_is_enabled(), used as a render-time gate in many places (chromeless rendering, admin-bar, payload generation, REST permission checks, etc.). Most call sites should benefit from the tighter gate. Risks worth thinking through before shipping:Suggested fix
desktop_mode_is_enabled()per above.docs/hooks-reference.mdanddocs/examples/gate-by-role.md.Related
Follow-up to #98.