PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.3
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.3
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / users-window / permissions.php

permissions.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.3, at includes/users-window/permissions.php

173 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — Native Users Window: capability gates.
4 *
5 * Multi-tier gating, parallel to WordPress core's `users.php` flow:
6 *
7 * - `list_users` → REGISTER the window. Cap-only check; the
8 * opt-in toggle is JS-side.
9 * - `edit_users` → mutation quick-actions (Send password reset,
10 * Resend welcome).
11 * - `promote_users` → bulk role-change action; per-target gated
12 * through {@see desktop_mode_users_window_assignable_roles()}.
13 * - `create_users` → "Add new user" toolbar button.
14 * - `delete_users` → bulk-delete (single-site).
15 * - `remove_users` → bulk-remove (multisite — removes from current site,
16 * leaves the network user record alone).
17 *
18 * UI-side gating is purely UX polish — the REST routes in `rest.php`
19 * re-validate every cap and every per-target permission before
20 * mutating anything.
21 *
22 * @package WPDesktopMode
23 * @since 0.8.1
24 */
25
26 defined( 'ABSPATH' ) || exit;
27
28 /**
29 * Whether the user is eligible to have the Users window registered.
30 *
31 * @since 0.8.1
32 *
33 * @param int|null $user_id Optional. Defaults to `get_current_user_id()`.
34 * @return bool
35 */
36 function desktop_mode_users_window_user_can_register( $user_id = null ) {
37 $user_id = null === $user_id ? get_current_user_id() : (int) $user_id;
38 $can = $user_id > 0 && user_can( $user_id, 'list_users' );
39
40 /**
41 * Filter whether the current user can have the Users window
42 * registered. This is the boot-time check; runtime "should the
43 * dock click use the native window?" is the JS-side
44 * `nativeUsersEnabled` flag.
45 *
46 * @since 0.8.1
47 *
48 * @param bool $can Default: `list_users` capability.
49 * @param int $user_id User being checked.
50 */
51 return (bool) apply_filters(
52 'desktop_mode_users_window_user_can_register',
53 $can,
54 $user_id
55 );
56 }
57
58 /**
59 * Combined cap-and-opt-in check. Used by callers that want the
60 * combined answer (e.g. analytics, an arrange-menu entry).
61 *
62 * @since 0.8.1
63 *
64 * @param int|null $user_id Optional.
65 * @return bool
66 */
67 function desktop_mode_users_window_user_can_use( $user_id = null ) {
68 $user_id = null === $user_id ? get_current_user_id() : (int) $user_id;
69
70 $cap_ok = desktop_mode_users_window_user_can_register( $user_id );
71
72 $opt_in = false;
73 if ( $cap_ok && function_exists( 'desktop_mode_get_os_settings' ) ) {
74 $settings = desktop_mode_get_os_settings( $user_id );
75 $opt_in = ! empty( $settings['nativeUsersEnabled'] );
76 }
77
78 $can = $cap_ok && $opt_in;
79
80 /**
81 * Filter whether the current user has opted into the native Users
82 * experience.
83 *
84 * @since 0.8.1
85 *
86 * @param bool $can Default gate result.
87 * @param int $user_id User being checked.
88 */
89 return (bool) apply_filters( 'desktop_mode_users_window_user_can_use', $can, $user_id );
90 }
91
92 /**
93 * Resolve the role slugs the current viewer is allowed to assign to
94 * the given target user.
95 *
96 * Honors core's `editable_roles` filter. Note core's default returns
97 * EVERY registered role (administrator included) to any user with
98 * `promote_users` — there is no built-in capability-subset hierarchy
99 * in core. Sites wanting stricter rules must filter `editable_roles`
100 * or `desktop_mode_users_window_assignable_roles` below. We compute
101 * the list server-side and surface it on the row so the UI can hide
102 * options the viewer can't apply; the REST mutation routes call this
103 * same filtered helper and reject anything outside it.
104 *
105 * @since 0.8.1
106 *
107 * @param int $viewer_id Requesting user.
108 * @param int $target_id Target user (optional — used by filters).
109 * @return string[] Role slugs the viewer can assign to the target.
110 */
111 function desktop_mode_users_window_assignable_roles( $viewer_id, $target_id = 0 ) {
112 $viewer_id = (int) $viewer_id;
113 if ( $viewer_id <= 0 || ! user_can( $viewer_id, 'promote_users' ) ) {
114 return array();
115 }
116
117 // Switch to the viewer's perspective so `current_user_can` and
118 // `get_editable_roles` evaluate against their caps, not whoever
119 // happens to be acting at REST-init time.
120 $prev_user = get_current_user_id();
121 $switched = false;
122 if ( $prev_user !== $viewer_id ) {
123 wp_set_current_user( $viewer_id );
124 $switched = true;
125 }
126
127 // `get_editable_roles()` lives in wp-admin/includes/user.php
128 // which is NOT auto-loaded by the time `init` fires (the hook
129 // our window registers on). Without this require_once the
130 // function doesn't exist, the array comes back empty, and the
131 // admin sees only the site's default_role ("subscriber") in
132 // the role dropdown — exactly the symptom that surfaced once
133 // real-world testing started.
134 if ( ! function_exists( 'get_editable_roles' ) ) {
135 require_once ABSPATH . 'wp-admin/includes/user.php';
136 }
137 $editable = function_exists( 'get_editable_roles' )
138 ? (array) get_editable_roles()
139 : array();
140
141 if ( $switched ) {
142 wp_set_current_user( $prev_user );
143 }
144
145 $slugs = array_keys( $editable );
146
147 /**
148 * Filter the role slugs assignable by `$viewer_id` to `$target_id`.
149 *
150 * Use this to LOCK DOWN role assignment further (e.g. "site
151 * managers can't promote anyone to administrator even if core
152 * would let them"). Returning an empty array fully disables role
153 * mutation for the viewer.
154 *
155 * Returning a SUPERSET widens the REST endpoints too — both the
156 * bulk-role route and the create-user route validate the requested
157 * role against this same filtered list (see `rest.php`), so only
158 * add roles you genuinely intend to make assignable.
159 *
160 * @since 0.8.1
161 *
162 * @param string[] $slugs Default role slug list.
163 * @param int $viewer_id
164 * @param int $target_id
165 */
166 return (array) apply_filters(
167 'desktop_mode_users_window_assignable_roles',
168 $slugs,
169 $viewer_id,
170 $target_id
171 );
172 }
173