This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Access users |
||
5 | */ |
||
6 | class WP_REST_Users_Controller extends WP_REST_Controller { |
||
7 | |||
8 | public function __construct() { |
||
9 | $this->namespace = 'wp/v2'; |
||
10 | $this->rest_base = 'users'; |
||
11 | } |
||
12 | |||
13 | /** |
||
14 | * Register the routes for the objects of the controller. |
||
15 | */ |
||
16 | public function register_routes() { |
||
17 | |||
18 | register_rest_route( $this->namespace, '/' . $this->rest_base, array( |
||
19 | array( |
||
20 | 'methods' => WP_REST_Server::READABLE, |
||
21 | 'callback' => array( $this, 'get_items' ), |
||
22 | 'permission_callback' => array( $this, 'get_items_permissions_check' ), |
||
23 | 'args' => $this->get_collection_params(), |
||
24 | ), |
||
25 | array( |
||
26 | 'methods' => WP_REST_Server::CREATABLE, |
||
27 | 'callback' => array( $this, 'create_item' ), |
||
28 | 'permission_callback' => array( $this, 'create_item_permissions_check' ), |
||
29 | 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), |
||
30 | ), |
||
31 | 'schema' => array( $this, 'get_public_item_schema' ), |
||
32 | ) ); |
||
33 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( |
||
34 | array( |
||
35 | 'methods' => WP_REST_Server::READABLE, |
||
36 | 'callback' => array( $this, 'get_item' ), |
||
37 | 'permission_callback' => array( $this, 'get_item_permissions_check' ), |
||
38 | 'args' => array( |
||
39 | 'context' => $this->get_context_param( array( 'default' => 'view' ) ), |
||
40 | ), |
||
41 | ), |
||
42 | array( |
||
43 | 'methods' => WP_REST_Server::EDITABLE, |
||
44 | 'callback' => array( $this, 'update_item' ), |
||
45 | 'permission_callback' => array( $this, 'update_item_permissions_check' ), |
||
46 | 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), |
||
47 | ), |
||
48 | array( |
||
49 | 'methods' => WP_REST_Server::DELETABLE, |
||
50 | 'callback' => array( $this, 'delete_item' ), |
||
51 | 'permission_callback' => array( $this, 'delete_item_permissions_check' ), |
||
52 | 'args' => array( |
||
53 | 'force' => array( |
||
54 | 'default' => false, |
||
55 | 'description' => __( 'Required to be true, as resource does not support trashing.' ), |
||
56 | ), |
||
57 | 'reassign' => array(), |
||
58 | ), |
||
59 | ), |
||
60 | 'schema' => array( $this, 'get_public_item_schema' ), |
||
61 | ) ); |
||
62 | |||
63 | register_rest_route( $this->namespace, '/' . $this->rest_base . '/me', array( |
||
64 | 'methods' => WP_REST_Server::READABLE, |
||
65 | 'callback' => array( $this, 'get_current_item' ), |
||
66 | 'args' => array( |
||
67 | 'context' => array(), |
||
68 | ), |
||
69 | 'schema' => array( $this, 'get_public_item_schema' ), |
||
70 | )); |
||
71 | } |
||
72 | |||
73 | /** |
||
74 | * Permissions check for getting all users. |
||
75 | * |
||
76 | * @param WP_REST_Request $request Full details about the request. |
||
77 | * @return WP_Error|boolean |
||
78 | */ |
||
79 | public function get_items_permissions_check( $request ) { |
||
80 | // Check if roles is specified in GET request and if user can list users. |
||
81 | if ( ! empty( $request['roles'] ) && ! current_user_can( 'list_users' ) ) { |
||
82 | return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you cannot filter by role.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
83 | } |
||
84 | |||
85 | if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) { |
||
86 | return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you cannot view this resource with edit context.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
87 | } |
||
88 | |||
89 | if ( in_array( $request['orderby'], array( 'email', 'registered_date' ), true ) && ! current_user_can( 'list_users' ) ) { |
||
90 | return new WP_Error( 'rest_forbidden_orderby', __( 'Sorry, you cannot order by this parameter.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
91 | } |
||
92 | |||
93 | return true; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Get all users |
||
98 | * |
||
99 | * @param WP_REST_Request $request Full details about the request. |
||
100 | * @return WP_Error|WP_REST_Response |
||
101 | */ |
||
102 | public function get_items( $request ) { |
||
103 | |||
104 | $prepared_args = array(); |
||
105 | $prepared_args['exclude'] = $request['exclude']; |
||
106 | $prepared_args['include'] = $request['include']; |
||
107 | $prepared_args['order'] = $request['order']; |
||
108 | $prepared_args['number'] = $request['per_page']; |
||
109 | View Code Duplication | if ( ! empty( $request['offset'] ) ) { |
|
110 | $prepared_args['offset'] = $request['offset']; |
||
111 | } else { |
||
112 | $prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number']; |
||
113 | } |
||
114 | $orderby_possibles = array( |
||
115 | 'id' => 'ID', |
||
116 | 'include' => 'include', |
||
117 | 'name' => 'display_name', |
||
118 | 'registered_date' => 'registered', |
||
119 | 'slug' => 'user_nicename', |
||
120 | 'email' => 'user_email', |
||
121 | 'url' => 'user_url', |
||
122 | ); |
||
123 | $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ]; |
||
124 | $prepared_args['search'] = $request['search']; |
||
125 | $prepared_args['role__in'] = $request['roles']; |
||
126 | |||
127 | if ( ! current_user_can( 'list_users' ) ) { |
||
128 | $prepared_args['has_published_posts'] = true; |
||
129 | } |
||
130 | |||
131 | if ( ! empty( $prepared_args['search'] ) ) { |
||
132 | $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; |
||
133 | } |
||
134 | |||
135 | if ( ! empty( $request['slug'] ) ) { |
||
136 | $prepared_args['search'] = $request['slug']; |
||
137 | $prepared_args['search_columns'] = array( 'user_nicename' ); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Filter arguments, before passing to WP_User_Query, when querying users via the REST API. |
||
142 | * |
||
143 | * @see https://developer.wordpress.org/reference/classes/wp_user_query/ |
||
144 | * |
||
145 | * @param array $prepared_args Array of arguments for WP_User_Query. |
||
146 | * @param WP_REST_Request $request The current request. |
||
147 | */ |
||
148 | $prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request ); |
||
149 | |||
150 | $query = new WP_User_Query( $prepared_args ); |
||
151 | |||
152 | $users = array(); |
||
153 | foreach ( $query->results as $user ) { |
||
154 | $data = $this->prepare_item_for_response( $user, $request ); |
||
155 | $users[] = $this->prepare_response_for_collection( $data ); |
||
156 | } |
||
157 | |||
158 | $response = rest_ensure_response( $users ); |
||
159 | |||
160 | // Store pagation values for headers then unset for count query. |
||
161 | $per_page = (int) $prepared_args['number']; |
||
162 | $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); |
||
163 | |||
164 | $prepared_args['fields'] = 'ID'; |
||
165 | |||
166 | $total_users = $query->get_total(); |
||
167 | if ( $total_users < 1 ) { |
||
168 | // Out-of-bounds, run the query again without LIMIT for total count |
||
169 | unset( $prepared_args['number'] ); |
||
170 | unset( $prepared_args['offset'] ); |
||
171 | $count_query = new WP_User_Query( $prepared_args ); |
||
172 | $total_users = $count_query->get_total(); |
||
173 | } |
||
174 | $response->header( 'X-WP-Total', (int) $total_users ); |
||
175 | $max_pages = ceil( $total_users / $per_page ); |
||
176 | $response->header( 'X-WP-TotalPages', (int) $max_pages ); |
||
177 | |||
178 | $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) ); |
||
179 | View Code Duplication | if ( $page > 1 ) { |
|
180 | $prev_page = $page - 1; |
||
181 | if ( $prev_page > $max_pages ) { |
||
182 | $prev_page = $max_pages; |
||
183 | } |
||
184 | $prev_link = add_query_arg( 'page', $prev_page, $base ); |
||
185 | $response->link_header( 'prev', $prev_link ); |
||
186 | } |
||
187 | View Code Duplication | if ( $max_pages > $page ) { |
|
188 | $next_page = $page + 1; |
||
189 | $next_link = add_query_arg( 'page', $next_page, $base ); |
||
190 | $response->link_header( 'next', $next_link ); |
||
191 | } |
||
192 | |||
193 | return $response; |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * Check if a given request has access to read a user |
||
198 | * |
||
199 | * @param WP_REST_Request $request Full details about the request. |
||
200 | * @return WP_Error|boolean |
||
201 | */ |
||
202 | public function get_item_permissions_check( $request ) { |
||
203 | |||
204 | $id = (int) $request['id']; |
||
205 | $user = get_userdata( $id ); |
||
206 | $types = get_post_types( array( 'show_in_rest' => true ), 'names' ); |
||
207 | |||
208 | if ( empty( $id ) || empty( $user->ID ) ) { |
||
209 | return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) ); |
||
210 | } |
||
211 | |||
212 | if ( get_current_user_id() === $id ) { |
||
213 | return true; |
||
214 | } |
||
215 | |||
216 | if ( 'edit' === $request['context'] && ! current_user_can( 'list_users' ) ) { |
||
217 | return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you cannot view this resource with edit context.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
218 | View Code Duplication | } else if ( ! count_user_posts( $id, $types ) && ! current_user_can( 'edit_user', $id ) && ! current_user_can( 'list_users' ) ) { |
|
219 | return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you cannot view this resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
220 | } |
||
221 | |||
222 | return true; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Get a single user |
||
227 | * |
||
228 | * @param WP_REST_Request $request Full details about the request. |
||
229 | * @return WP_Error|WP_REST_Response |
||
230 | */ |
||
231 | public function get_item( $request ) { |
||
232 | $id = (int) $request['id']; |
||
233 | $user = get_userdata( $id ); |
||
234 | |||
235 | if ( empty( $id ) || empty( $user->ID ) ) { |
||
236 | return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) ); |
||
237 | } |
||
238 | |||
239 | $user = $this->prepare_item_for_response( $user, $request ); |
||
240 | $response = rest_ensure_response( $user ); |
||
241 | |||
242 | return $response; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Get the current user |
||
247 | * |
||
248 | * @param WP_REST_Request $request Full details about the request. |
||
249 | * @return WP_Error|WP_REST_Response |
||
250 | */ |
||
251 | public function get_current_item( $request ) { |
||
252 | $current_user_id = get_current_user_id(); |
||
253 | if ( empty( $current_user_id ) ) { |
||
254 | return new WP_Error( 'rest_not_logged_in', __( 'You are not currently logged in.' ), array( 'status' => 401 ) ); |
||
255 | } |
||
256 | |||
257 | $user = wp_get_current_user(); |
||
258 | $response = $this->prepare_item_for_response( $user, $request ); |
||
259 | $response = rest_ensure_response( $response ); |
||
260 | $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $current_user_id ) ) ); |
||
261 | $response->set_status( 302 ); |
||
262 | |||
263 | return $response; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Check if a given request has access create users |
||
268 | * |
||
269 | * @param WP_REST_Request $request Full details about the request. |
||
270 | * @return boolean |
||
271 | */ |
||
272 | public function create_item_permissions_check( $request ) { |
||
273 | |||
274 | if ( ! current_user_can( 'create_users' ) ) { |
||
275 | return new WP_Error( 'rest_cannot_create_user', __( 'Sorry, you are not allowed to create resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
276 | } |
||
277 | |||
278 | return true; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Create a single user |
||
283 | * |
||
284 | * @param WP_REST_Request $request Full details about the request. |
||
285 | * @return WP_Error|WP_REST_Response |
||
286 | */ |
||
287 | public function create_item( $request ) { |
||
288 | if ( ! empty( $request['id'] ) ) { |
||
289 | return new WP_Error( 'rest_user_exists', __( 'Cannot create existing resource.' ), array( 'status' => 400 ) ); |
||
290 | } |
||
291 | |||
292 | $schema = $this->get_item_schema(); |
||
293 | |||
294 | if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { |
||
295 | $check_permission = $this->check_role_update( $request['id'], $request['roles'] ); |
||
0 ignored issues
–
show
Bug
Compatibility
introduced
by
Loading history...
|
|||
296 | if ( is_wp_error( $check_permission ) ) { |
||
297 | return $check_permission; |
||
298 | } |
||
299 | } |
||
300 | |||
301 | $user = $this->prepare_item_for_database( $request ); |
||
302 | |||
303 | if ( is_multisite() ) { |
||
304 | $ret = wpmu_validate_user_signup( $user->user_login, $user->user_email ); |
||
305 | if ( is_wp_error( $ret['errors'] ) && ! empty( $ret['errors']->errors ) ) { |
||
306 | return $ret['errors']; |
||
307 | } |
||
308 | } |
||
309 | |||
310 | if ( is_multisite() ) { |
||
311 | $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); |
||
312 | if ( ! $user_id ) { |
||
313 | return new WP_Error( 'rest_user_create', __( 'Error creating new resource.' ), array( 'status' => 500 ) ); |
||
314 | } |
||
315 | $user->ID = $user_id; |
||
316 | $user_id = wp_update_user( $user ); |
||
317 | if ( is_wp_error( $user_id ) ) { |
||
318 | return $user_id; |
||
319 | } |
||
320 | } else { |
||
321 | $user_id = wp_insert_user( $user ); |
||
322 | if ( is_wp_error( $user_id ) ) { |
||
323 | return $user_id; |
||
324 | } |
||
325 | } |
||
326 | |||
327 | $user = get_user_by( 'id', $user_id ); |
||
328 | if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) { |
||
329 | array_map( array( $user, 'add_role' ), $request['roles'] ); |
||
330 | } |
||
331 | |||
332 | $fields_update = $this->update_additional_fields_for_object( $user, $request ); |
||
333 | if ( is_wp_error( $fields_update ) ) { |
||
334 | return $fields_update; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Fires after a user is created or updated via the REST API. |
||
339 | * |
||
340 | * @param WP_User $user Data used to create the user. |
||
341 | * @param WP_REST_Request $request Request object. |
||
342 | * @param boolean $creating True when creating user, false when updating user. |
||
343 | */ |
||
344 | do_action( 'rest_insert_user', $user, $request, true ); |
||
345 | |||
346 | $request->set_param( 'context', 'edit' ); |
||
347 | $response = $this->prepare_item_for_response( $user, $request ); |
||
348 | $response = rest_ensure_response( $response ); |
||
349 | $response->set_status( 201 ); |
||
350 | $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user_id ) ) ); |
||
351 | |||
352 | return $response; |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Check if a given request has access update a user |
||
357 | * |
||
358 | * @param WP_REST_Request $request Full details about the request. |
||
359 | * @return boolean |
||
360 | */ |
||
361 | public function update_item_permissions_check( $request ) { |
||
362 | |||
363 | $id = (int) $request['id']; |
||
364 | |||
365 | if ( ! current_user_can( 'edit_user', $id ) ) { |
||
366 | return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
367 | } |
||
368 | |||
369 | if ( ! empty( $request['roles'] ) && ! current_user_can( 'edit_users' ) ) { |
||
370 | return new WP_Error( 'rest_cannot_edit_roles', __( 'Sorry, you are not allowed to edit roles of this resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
371 | } |
||
372 | |||
373 | return true; |
||
374 | } |
||
375 | |||
376 | /** |
||
377 | * Update a single user |
||
378 | * |
||
379 | * @param WP_REST_Request $request Full details about the request. |
||
380 | * @return WP_Error|WP_REST_Response |
||
381 | */ |
||
382 | public function update_item( $request ) { |
||
383 | $id = (int) $request['id']; |
||
384 | |||
385 | $user = get_userdata( $id ); |
||
386 | if ( ! $user ) { |
||
387 | return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) ); |
||
388 | } |
||
389 | |||
390 | if ( email_exists( $request['email'] ) && $request['email'] !== $user->user_email ) { |
||
391 | return new WP_Error( 'rest_user_invalid_email', __( 'Email address is invalid.' ), array( 'status' => 400 ) ); |
||
392 | } |
||
393 | |||
394 | if ( ! empty( $request['username'] ) && $request['username'] !== $user->user_login ) { |
||
395 | return new WP_Error( 'rest_user_invalid_argument', __( "Username isn't editable" ), array( 'status' => 400 ) ); |
||
396 | } |
||
397 | |||
398 | View Code Duplication | if ( ! empty( $request['slug'] ) && $request['slug'] !== $user->user_nicename && get_user_by( 'slug', $request['slug'] ) ) { |
|
399 | return new WP_Error( 'rest_user_invalid_slug', __( 'Slug is invalid.' ), array( 'status' => 400 ) ); |
||
400 | } |
||
401 | |||
402 | if ( ! empty( $request['roles'] ) ) { |
||
403 | $check_permission = $this->check_role_update( $id, $request['roles'] ); |
||
404 | if ( is_wp_error( $check_permission ) ) { |
||
405 | return $check_permission; |
||
406 | } |
||
407 | } |
||
408 | |||
409 | $user = $this->prepare_item_for_database( $request ); |
||
410 | |||
411 | // Ensure we're operating on the same user we already checked |
||
412 | $user->ID = $id; |
||
413 | |||
414 | $user_id = wp_update_user( $user ); |
||
415 | if ( is_wp_error( $user_id ) ) { |
||
416 | return $user_id; |
||
417 | } |
||
418 | |||
419 | $user = get_user_by( 'id', $id ); |
||
420 | if ( ! empty( $request['roles'] ) ) { |
||
421 | array_map( array( $user, 'add_role' ), $request['roles'] ); |
||
422 | } |
||
423 | |||
424 | $fields_update = $this->update_additional_fields_for_object( $user, $request ); |
||
425 | if ( is_wp_error( $fields_update ) ) { |
||
426 | return $fields_update; |
||
427 | } |
||
428 | |||
429 | /* This action is documented in lib/endpoints/class-wp-rest-users-controller.php */ |
||
430 | do_action( 'rest_insert_user', $user, $request, false ); |
||
431 | |||
432 | $request->set_param( 'context', 'edit' ); |
||
433 | $response = $this->prepare_item_for_response( $user, $request ); |
||
434 | $response = rest_ensure_response( $response ); |
||
435 | return $response; |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * Check if a given request has access delete a user |
||
440 | * |
||
441 | * @param WP_REST_Request $request Full details about the request. |
||
442 | * @return boolean |
||
443 | */ |
||
444 | public function delete_item_permissions_check( $request ) { |
||
445 | |||
446 | $id = (int) $request['id']; |
||
447 | |||
448 | if ( ! current_user_can( 'delete_user', $id ) ) { |
||
449 | return new WP_Error( 'rest_user_cannot_delete', __( 'Sorry, you are not allowed to delete this resource.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
450 | } |
||
451 | |||
452 | return true; |
||
453 | } |
||
454 | |||
455 | /** |
||
456 | * Delete a single user |
||
457 | * |
||
458 | * @param WP_REST_Request $request Full details about the request. |
||
459 | * @return WP_Error|WP_REST_Response |
||
460 | */ |
||
461 | public function delete_item( $request ) { |
||
462 | $id = (int) $request['id']; |
||
463 | $reassign = isset( $request['reassign'] ) ? absint( $request['reassign'] ) : null; |
||
464 | $force = isset( $request['force'] ) ? (bool) $request['force'] : false; |
||
465 | |||
466 | // We don't support trashing for this type, error out |
||
467 | if ( ! $force ) { |
||
468 | return new WP_Error( 'rest_trash_not_supported', __( 'Users do not support trashing.' ), array( 'status' => 501 ) ); |
||
469 | } |
||
470 | |||
471 | $user = get_userdata( $id ); |
||
472 | if ( ! $user ) { |
||
473 | return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) ); |
||
474 | } |
||
475 | |||
476 | View Code Duplication | if ( ! empty( $reassign ) ) { |
|
477 | if ( $reassign === $id || ! get_userdata( $reassign ) ) { |
||
478 | return new WP_Error( 'rest_user_invalid_reassign', __( 'Invalid resource id for reassignment.' ), array( 'status' => 400 ) ); |
||
479 | } |
||
480 | } |
||
481 | |||
482 | $request->set_param( 'context', 'edit' ); |
||
483 | $response = $this->prepare_item_for_response( $user, $request ); |
||
484 | |||
485 | /** Include admin user functions to get access to wp_delete_user() */ |
||
486 | require_once ABSPATH . 'wp-admin/includes/user.php'; |
||
487 | |||
488 | $result = wp_delete_user( $id, $reassign ); |
||
489 | |||
490 | if ( ! $result ) { |
||
491 | return new WP_Error( 'rest_cannot_delete', __( 'The resource cannot be deleted.' ), array( 'status' => 500 ) ); |
||
492 | } |
||
493 | |||
494 | /** |
||
495 | * Fires after a user is deleted via the REST API. |
||
496 | * |
||
497 | * @param WP_User $user The user data. |
||
498 | * @param WP_REST_Response $response The response returned from the API. |
||
499 | * @param WP_REST_Request $request The request sent to the API. |
||
500 | */ |
||
501 | do_action( 'rest_delete_user', $user, $response, $request ); |
||
502 | |||
503 | return $response; |
||
504 | } |
||
505 | |||
506 | /** |
||
507 | * Prepare a single user output for response |
||
508 | * |
||
509 | * @param object $user User object. |
||
510 | * @param WP_REST_Request $request Request object. |
||
511 | * @return WP_REST_Response $response Response data. |
||
512 | */ |
||
513 | public function prepare_item_for_response( $user, $request ) { |
||
514 | |||
515 | $data = array(); |
||
516 | $schema = $this->get_item_schema(); |
||
517 | if ( ! empty( $schema['properties']['id'] ) ) { |
||
518 | $data['id'] = $user->ID; |
||
519 | } |
||
520 | |||
521 | if ( ! empty( $schema['properties']['username'] ) ) { |
||
522 | $data['username'] = $user->user_login; |
||
523 | } |
||
524 | |||
525 | if ( ! empty( $schema['properties']['name'] ) ) { |
||
526 | $data['name'] = $user->display_name; |
||
527 | } |
||
528 | |||
529 | if ( ! empty( $schema['properties']['first_name'] ) ) { |
||
530 | $data['first_name'] = $user->first_name; |
||
531 | } |
||
532 | |||
533 | if ( ! empty( $schema['properties']['last_name'] ) ) { |
||
534 | $data['last_name'] = $user->last_name; |
||
535 | } |
||
536 | |||
537 | if ( ! empty( $schema['properties']['email'] ) ) { |
||
538 | $data['email'] = $user->user_email; |
||
539 | } |
||
540 | |||
541 | if ( ! empty( $schema['properties']['url'] ) ) { |
||
542 | $data['url'] = $user->user_url; |
||
543 | } |
||
544 | |||
545 | if ( ! empty( $schema['properties']['description'] ) ) { |
||
546 | $data['description'] = $user->description; |
||
547 | } |
||
548 | |||
549 | if ( ! empty( $schema['properties']['link'] ) ) { |
||
550 | $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename ); |
||
551 | } |
||
552 | |||
553 | if ( ! empty( $schema['properties']['nickname'] ) ) { |
||
554 | $data['nickname'] = $user->nickname; |
||
555 | } |
||
556 | |||
557 | if ( ! empty( $schema['properties']['slug'] ) ) { |
||
558 | $data['slug'] = $user->user_nicename; |
||
559 | } |
||
560 | |||
561 | if ( ! empty( $schema['properties']['roles'] ) ) { |
||
562 | // Defensively call array_values() to ensure an array is returned. |
||
563 | $data['roles'] = array_values( $user->roles ); |
||
564 | } |
||
565 | |||
566 | if ( ! empty( $schema['properties']['registered_date'] ) ) { |
||
567 | $data['registered_date'] = date( 'c', strtotime( $user->user_registered ) ); |
||
568 | } |
||
569 | |||
570 | if ( ! empty( $schema['properties']['capabilities'] ) ) { |
||
571 | $data['capabilities'] = (object) $user->allcaps; |
||
572 | } |
||
573 | |||
574 | if ( ! empty( $schema['properties']['extra_capabilities'] ) ) { |
||
575 | $data['extra_capabilities'] = (object) $user->caps; |
||
576 | } |
||
577 | |||
578 | if ( ! empty( $schema['properties']['avatar_urls'] ) ) { |
||
579 | $data['avatar_urls'] = rest_get_avatar_urls( $user->user_email ); |
||
580 | } |
||
581 | |||
582 | $context = ! empty( $request['context'] ) ? $request['context'] : 'embed'; |
||
583 | |||
584 | $data = $this->add_additional_fields_to_object( $data, $request ); |
||
585 | $data = $this->filter_response_by_context( $data, $context ); |
||
586 | |||
587 | // Wrap the data in a response object |
||
588 | $response = rest_ensure_response( $data ); |
||
589 | |||
590 | $response->add_links( $this->prepare_links( $user ) ); |
||
591 | |||
592 | /** |
||
593 | * Filter user data returned from the REST API. |
||
594 | * |
||
595 | * @param WP_REST_Response $response The response object. |
||
596 | * @param object $user User object used to create response. |
||
597 | * @param WP_REST_Request $request Request object. |
||
598 | */ |
||
599 | return apply_filters( 'rest_prepare_user', $response, $user, $request ); |
||
600 | } |
||
601 | |||
602 | /** |
||
603 | * Prepare links for the request. |
||
604 | * |
||
605 | * @param WP_Post $user User object. |
||
606 | * @return array Links for the given user. |
||
607 | */ |
||
608 | protected function prepare_links( $user ) { |
||
609 | $links = array( |
||
610 | 'self' => array( |
||
611 | 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ), |
||
612 | ), |
||
613 | 'collection' => array( |
||
614 | 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), |
||
615 | ), |
||
616 | ); |
||
617 | |||
618 | return $links; |
||
619 | } |
||
620 | |||
621 | /** |
||
622 | * Prepare a single user for create or update |
||
623 | * |
||
624 | * @param WP_REST_Request $request Request object. |
||
625 | * @return object $prepared_user User object. |
||
626 | */ |
||
627 | protected function prepare_item_for_database( $request ) { |
||
628 | $prepared_user = new stdClass; |
||
629 | |||
630 | $schema = $this->get_item_schema(); |
||
631 | |||
632 | // required arguments. |
||
633 | if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) { |
||
634 | $prepared_user->user_email = $request['email']; |
||
635 | } |
||
636 | if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) { |
||
637 | $prepared_user->user_login = $request['username']; |
||
638 | } |
||
639 | if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) { |
||
640 | $prepared_user->user_pass = $request['password']; |
||
641 | } |
||
642 | |||
643 | // optional arguments. |
||
644 | if ( isset( $request['id'] ) ) { |
||
645 | $prepared_user->ID = absint( $request['id'] ); |
||
646 | } |
||
647 | View Code Duplication | if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) { |
|
648 | $prepared_user->display_name = $request['name']; |
||
649 | } |
||
650 | View Code Duplication | if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) { |
|
651 | $prepared_user->first_name = $request['first_name']; |
||
652 | } |
||
653 | View Code Duplication | if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) { |
|
654 | $prepared_user->last_name = $request['last_name']; |
||
655 | } |
||
656 | View Code Duplication | if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) { |
|
657 | $prepared_user->nickname = $request['nickname']; |
||
658 | } |
||
659 | View Code Duplication | if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) { |
|
660 | $prepared_user->user_nicename = $request['slug']; |
||
661 | } |
||
662 | View Code Duplication | if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) { |
|
663 | $prepared_user->description = $request['description']; |
||
664 | } |
||
665 | |||
666 | View Code Duplication | if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) { |
|
667 | $prepared_user->user_url = $request['url']; |
||
668 | } |
||
669 | |||
670 | // setting roles will be handled outside of this function. |
||
671 | if ( isset( $request['roles'] ) ) { |
||
672 | $prepared_user->role = false; |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * Filter user data before inserting user via the REST API. |
||
677 | * |
||
678 | * @param object $prepared_user User object. |
||
679 | * @param WP_REST_Request $request Request object. |
||
680 | */ |
||
681 | return apply_filters( 'rest_pre_insert_user', $prepared_user, $request ); |
||
682 | } |
||
683 | |||
684 | /** |
||
685 | * Determine if the current user is allowed to make the desired roles change. |
||
686 | * |
||
687 | * @param integer $user_id |
||
688 | * @param array $roles |
||
689 | * @return WP_Error|boolean |
||
690 | */ |
||
691 | protected function check_role_update( $user_id, $roles ) { |
||
692 | global $wp_roles; |
||
693 | |||
694 | foreach ( $roles as $role ) { |
||
695 | |||
696 | if ( ! isset( $wp_roles->role_objects[ $role ] ) ) { |
||
697 | return new WP_Error( 'rest_user_invalid_role', sprintf( __( 'The role %s does not exist.' ), $role ), array( 'status' => 400 ) ); |
||
698 | } |
||
699 | |||
700 | $potential_role = $wp_roles->role_objects[ $role ]; |
||
701 | // Don't let anyone with 'edit_users' (admins) edit their own role to something without it. |
||
702 | // Multisite super admins can freely edit their blog roles -- they possess all caps. |
||
703 | View Code Duplication | if ( ! ( is_multisite() && current_user_can( 'manage_sites' ) ) && get_current_user_id() === $user_id && ! $potential_role->has_cap( 'edit_users' ) ) { |
|
704 | return new WP_Error( 'rest_user_invalid_role', __( 'You cannot give resource that role.' ), array( 'status' => rest_authorization_required_code() ) ); |
||
705 | } |
||
706 | |||
707 | // The new role must be editable by the logged-in user. |
||
708 | |||
709 | /** Include admin functions to get access to get_editable_roles() */ |
||
710 | require_once ABSPATH . 'wp-admin/includes/admin.php'; |
||
711 | |||
712 | $editable_roles = get_editable_roles(); |
||
713 | if ( empty( $editable_roles[ $role ] ) ) { |
||
714 | return new WP_Error( 'rest_user_invalid_role', __( 'You cannot give resource that role.' ), array( 'status' => 403 ) ); |
||
715 | } |
||
716 | } |
||
717 | |||
718 | return true; |
||
719 | |||
720 | } |
||
721 | |||
722 | /** |
||
723 | * Get the User's schema, conforming to JSON Schema |
||
724 | * |
||
725 | * @return array |
||
726 | */ |
||
727 | public function get_item_schema() { |
||
728 | $schema = array( |
||
729 | '$schema' => 'http://json-schema.org/draft-04/schema#', |
||
730 | 'title' => 'user', |
||
731 | 'type' => 'object', |
||
732 | 'properties' => array( |
||
733 | 'id' => array( |
||
734 | 'description' => __( 'Unique identifier for the resource.' ), |
||
735 | 'type' => 'integer', |
||
736 | 'context' => array( 'embed', 'view', 'edit' ), |
||
737 | 'readonly' => true, |
||
738 | ), |
||
739 | 'username' => array( |
||
740 | 'description' => __( 'Login name for the resource.' ), |
||
741 | 'type' => 'string', |
||
742 | 'context' => array( 'edit' ), |
||
743 | 'required' => true, |
||
744 | 'arg_options' => array( |
||
745 | 'sanitize_callback' => 'sanitize_user', |
||
746 | ), |
||
747 | ), |
||
748 | 'name' => array( |
||
749 | 'description' => __( 'Display name for the resource.' ), |
||
750 | 'type' => 'string', |
||
751 | 'context' => array( 'embed', 'view', 'edit' ), |
||
752 | 'arg_options' => array( |
||
753 | 'sanitize_callback' => 'sanitize_text_field', |
||
754 | ), |
||
755 | ), |
||
756 | 'first_name' => array( |
||
757 | 'description' => __( 'First name for the resource.' ), |
||
758 | 'type' => 'string', |
||
759 | 'context' => array( 'edit' ), |
||
760 | 'arg_options' => array( |
||
761 | 'sanitize_callback' => 'sanitize_text_field', |
||
762 | ), |
||
763 | ), |
||
764 | 'last_name' => array( |
||
765 | 'description' => __( 'Last name for the resource.' ), |
||
766 | 'type' => 'string', |
||
767 | 'context' => array( 'edit' ), |
||
768 | 'arg_options' => array( |
||
769 | 'sanitize_callback' => 'sanitize_text_field', |
||
770 | ), |
||
771 | ), |
||
772 | 'email' => array( |
||
773 | 'description' => __( 'The email address for the resource.' ), |
||
774 | 'type' => 'string', |
||
775 | 'format' => 'email', |
||
776 | 'context' => array( 'edit' ), |
||
777 | 'required' => true, |
||
778 | ), |
||
779 | 'url' => array( |
||
780 | 'description' => __( 'URL of the resource.' ), |
||
781 | 'type' => 'string', |
||
782 | 'format' => 'uri', |
||
783 | 'context' => array( 'embed', 'view', 'edit' ), |
||
784 | ), |
||
785 | 'description' => array( |
||
786 | 'description' => __( 'Description of the resource.' ), |
||
787 | 'type' => 'string', |
||
788 | 'context' => array( 'embed', 'view', 'edit' ), |
||
789 | 'arg_options' => array( |
||
790 | 'sanitize_callback' => 'wp_filter_post_kses', |
||
791 | ), |
||
792 | ), |
||
793 | 'link' => array( |
||
794 | 'description' => __( 'Author URL to the resource.' ), |
||
795 | 'type' => 'string', |
||
796 | 'format' => 'uri', |
||
797 | 'context' => array( 'embed', 'view', 'edit' ), |
||
798 | 'readonly' => true, |
||
799 | ), |
||
800 | 'nickname' => array( |
||
801 | 'description' => __( 'The nickname for the resource.' ), |
||
802 | 'type' => 'string', |
||
803 | 'context' => array( 'edit' ), |
||
804 | 'arg_options' => array( |
||
805 | 'sanitize_callback' => 'sanitize_text_field', |
||
806 | ), |
||
807 | ), |
||
808 | 'slug' => array( |
||
809 | 'description' => __( 'An alphanumeric identifier for the resource.' ), |
||
810 | 'type' => 'string', |
||
811 | 'context' => array( 'embed', 'view', 'edit' ), |
||
812 | 'arg_options' => array( |
||
813 | 'sanitize_callback' => array( $this, 'sanitize_slug' ), |
||
814 | ), |
||
815 | ), |
||
816 | 'registered_date' => array( |
||
817 | 'description' => __( 'Registration date for the resource.' ), |
||
818 | 'type' => 'string', |
||
819 | 'format' => 'date-time', |
||
820 | 'context' => array( 'edit' ), |
||
821 | 'readonly' => true, |
||
822 | ), |
||
823 | 'roles' => array( |
||
824 | 'description' => __( 'Roles assigned to the resource.' ), |
||
825 | 'type' => 'array', |
||
826 | 'context' => array( 'edit' ), |
||
827 | ), |
||
828 | 'password' => array( |
||
829 | 'description' => __( 'Password for the resource (never included).' ), |
||
830 | 'type' => 'string', |
||
831 | 'context' => array(), // Password is never displayed |
||
832 | 'required' => true, |
||
833 | ), |
||
834 | 'capabilities' => array( |
||
835 | 'description' => __( 'All capabilities assigned to the resource.' ), |
||
836 | 'type' => 'object', |
||
837 | 'context' => array( 'edit' ), |
||
838 | 'readonly' => true, |
||
839 | ), |
||
840 | 'extra_capabilities' => array( |
||
841 | 'description' => __( 'Any extra capabilities assigned to the resource.' ), |
||
842 | 'type' => 'object', |
||
843 | 'context' => array( 'edit' ), |
||
844 | 'readonly' => true, |
||
845 | ), |
||
846 | ), |
||
847 | ); |
||
848 | |||
849 | View Code Duplication | if ( get_option( 'show_avatars' ) ) { |
|
850 | $avatar_properties = array(); |
||
851 | |||
852 | $avatar_sizes = rest_get_avatar_sizes(); |
||
853 | foreach ( $avatar_sizes as $size ) { |
||
854 | $avatar_properties[ $size ] = array( |
||
855 | 'description' => sprintf( __( 'Avatar URL with image size of %d pixels.' ), $size ), |
||
856 | 'type' => 'string', |
||
857 | 'format' => 'uri', |
||
858 | 'context' => array( 'embed', 'view', 'edit' ), |
||
859 | ); |
||
860 | } |
||
861 | |||
862 | $schema['properties']['avatar_urls'] = array( |
||
863 | 'description' => __( 'Avatar URLs for the resource.' ), |
||
864 | 'type' => 'object', |
||
865 | 'context' => array( 'embed', 'view', 'edit' ), |
||
866 | 'readonly' => true, |
||
867 | 'properties' => $avatar_properties, |
||
868 | ); |
||
869 | |||
870 | } |
||
871 | |||
872 | return $this->add_additional_fields_schema( $schema ); |
||
873 | } |
||
874 | |||
875 | /** |
||
876 | * Get the query params for collections |
||
877 | * |
||
878 | * @return array |
||
879 | */ |
||
880 | public function get_collection_params() { |
||
881 | $query_params = parent::get_collection_params(); |
||
882 | |||
883 | $query_params['context']['default'] = 'view'; |
||
884 | |||
885 | $query_params['exclude'] = array( |
||
886 | 'description' => __( 'Ensure result set excludes specific ids.' ), |
||
887 | 'type' => 'array', |
||
888 | 'default' => array(), |
||
889 | 'sanitize_callback' => 'wp_parse_id_list', |
||
890 | ); |
||
891 | $query_params['include'] = array( |
||
892 | 'description' => __( 'Limit result set to specific ids.' ), |
||
893 | 'type' => 'array', |
||
894 | 'default' => array(), |
||
895 | 'sanitize_callback' => 'wp_parse_id_list', |
||
896 | ); |
||
897 | $query_params['offset'] = array( |
||
898 | 'description' => __( 'Offset the result set by a specific number of items.' ), |
||
899 | 'type' => 'integer', |
||
900 | 'sanitize_callback' => 'absint', |
||
901 | 'validate_callback' => 'rest_validate_request_arg', |
||
902 | ); |
||
903 | $query_params['order'] = array( |
||
904 | 'default' => 'asc', |
||
905 | 'description' => __( 'Order sort attribute ascending or descending.' ), |
||
906 | 'enum' => array( 'asc', 'desc' ), |
||
907 | 'sanitize_callback' => 'sanitize_key', |
||
908 | 'type' => 'string', |
||
909 | 'validate_callback' => 'rest_validate_request_arg', |
||
910 | ); |
||
911 | $query_params['orderby'] = array( |
||
912 | 'default' => 'name', |
||
913 | 'description' => __( 'Sort collection by object attribute.' ), |
||
914 | 'enum' => array( |
||
915 | 'id', |
||
916 | 'include', |
||
917 | 'name', |
||
918 | 'registered_date', |
||
919 | 'slug', |
||
920 | 'email', |
||
921 | 'url', |
||
922 | ), |
||
923 | 'sanitize_callback' => 'sanitize_key', |
||
924 | 'type' => 'string', |
||
925 | 'validate_callback' => 'rest_validate_request_arg', |
||
926 | ); |
||
927 | $query_params['slug'] = array( |
||
928 | 'description' => __( 'Limit result set to resources with a specific slug.' ), |
||
929 | 'type' => 'string', |
||
930 | 'validate_callback' => 'rest_validate_request_arg', |
||
931 | ); |
||
932 | $query_params['roles'] = array( |
||
933 | 'description' => __( 'Limit result set to resources matching at least one specific role provided. Accepts csv list or single role.' ), |
||
934 | 'type' => 'array', |
||
935 | 'sanitize_callback' => 'wp_parse_slug_list', |
||
936 | ); |
||
937 | return $query_params; |
||
938 | } |
||
939 | } |
||
940 |