PluginProbe
Notibar – Notification Bar for WordPress / trunk
Notibar – Notification Bar for WordPress vtrunk
3.2.2 3.2.1.1 3.2.1 3.1.5 3.1.4 3.1.1 3.1.0 trunk 1.9.2 1.9.3 2.0 2.1.1 2.1.4 2.1.5 2.1.6 2.1.8 2.1.9
notibar / includes / NotificationBar / RestUsersController.php

RestUsersController.php in Notibar – Notification Bar for WordPress trunk, at includes/NotificationBar/RestUsersController.php

164 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * REST API controller for user search — powers the per-bar audience "specific
4 * users" picker in the Customizer SPA (Pro feature).
5 *
6 * Namespace: notibar/v1
7 * Routes:
8 * GET /users — paginated search, returns { items, hasMore }
9 * GET /users/by-ids — hydrate selected chips by user IDs
10 *
11 * Permission: edit_theme_options (matches the Customizer capability). Admin-
12 * only; the endpoint exposes only id + display name, which such users can
13 * already see in wp-admin → Users.
14 *
15 * @package NjtNotificationBar\NotificationBar
16 */
17
18 namespace NjtNotificationBar\NotificationBar;
19
20 defined( 'ABSPATH' ) || exit;
21
22 class RestUsersController {
23
24 const NAMESPACE = 'notibar/v1';
25 const PER_PAGE = 20;
26
27 /**
28 * Register REST routes on rest_api_init.
29 *
30 * @return void
31 */
32 public function register(): void {
33 register_rest_route(
34 self::NAMESPACE,
35 '/users',
36 [
37 'methods' => \WP_REST_Server::READABLE,
38 'callback' => [ $this, 'handle_search' ],
39 'permission_callback' => [ $this, 'check_permission' ],
40 'args' => [
41 'q' => [
42 'default' => '',
43 'sanitize_callback' => 'sanitize_text_field',
44 ],
45 'page' => [
46 'default' => 1,
47 'sanitize_callback' => 'absint',
48 ],
49 ],
50 ]
51 );
52
53 register_rest_route(
54 self::NAMESPACE,
55 '/users/by-ids',
56 [
57 'methods' => \WP_REST_Server::READABLE,
58 'callback' => [ $this, 'handle_by_ids' ],
59 'permission_callback' => [ $this, 'check_permission' ],
60 'args' => [
61 'ids' => [
62 'default' => '',
63 'sanitize_callback' => 'sanitize_text_field',
64 ],
65 ],
66 ]
67 );
68 }
69
70 /**
71 * @return bool
72 */
73 public function check_permission(): bool {
74 return current_user_can( 'edit_theme_options' );
75 }
76
77 /**
78 * GET /users — paginated search.
79 *
80 * @param \WP_REST_Request $request Incoming request.
81 * @return \WP_REST_Response
82 */
83 public function handle_search( \WP_REST_Request $request ): \WP_REST_Response {
84 $q = (string) $request['q'];
85 $paged = max( 1, (int) $request['page'] );
86
87 $args = [
88 'number' => self::PER_PAGE,
89 'paged' => $paged,
90 'orderby' => 'display_name',
91 'order' => 'ASC',
92 'fields' => [ 'ID', 'display_name', 'user_login' ],
93 ];
94
95 if ( '' !== $q ) {
96 $args['search'] = '*' . $q . '*';
97 $args['search_columns'] = [ 'user_login', 'display_name', 'user_email', 'user_nicename' ];
98 }
99
100 $query = new \WP_User_Query( $args );
101 $items = array_map( [ self::class, 'map_user' ], $query->get_results() );
102
103 $total = (int) $query->get_total();
104 $has_more = ( $paged * self::PER_PAGE ) < $total;
105
106 return rest_ensure_response( [
107 'items' => $items,
108 'hasMore' => $has_more,
109 ] );
110 }
111
112 /**
113 * GET /users/by-ids — hydrate selected IDs for chip rendering.
114 *
115 * @param \WP_REST_Request $request Incoming request.
116 * @return \WP_REST_Response
117 */
118 public function handle_by_ids( \WP_REST_Request $request ): \WP_REST_Response {
119 $raw = (string) $request['ids'];
120 if ( '' === $raw ) {
121 return rest_ensure_response( [ 'items' => [] ] );
122 }
123
124 $ids = array_slice(
125 array_values( array_filter(
126 array_map( 'intval', explode( ',', $raw ) ),
127 fn( $v ) => $v > 0
128 ) ),
129 0,
130 self::PER_PAGE
131 );
132
133 if ( empty( $ids ) ) {
134 return rest_ensure_response( [ 'items' => [] ] );
135 }
136
137 $query = new \WP_User_Query( [
138 'include' => $ids,
139 'number' => count( $ids ),
140 'fields' => [ 'ID', 'display_name', 'user_login' ],
141 ] );
142
143 return rest_ensure_response( [
144 'items' => array_map( [ self::class, 'map_user' ], $query->get_results() ),
145 ] );
146 }
147
148 /**
149 * Shape a user row into the REST item dict.
150 *
151 * @param object $u User row (ID, display_name, user_login).
152 * @return array{id:int,title:string}
153 */
154 private static function map_user( $u ): array {
155 $name = isset( $u->display_name ) && '' !== $u->display_name
156 ? $u->display_name
157 : ( $u->user_login ?? '' );
158 return [
159 'id' => (int) $u->ID,
160 'title' => $name . ' (#' . (int) $u->ID . ')',
161 ];
162 }
163 }
164