Skip to content

Commit e0d1214

Browse files
committed
Abilities: Add core/get-user ability to retrieve user profile by id, username, or email
- Registers a new core/get-user ability in the user category that allows looking up any user by id, username, or email when permissions allow it. - Permission model: logged-in users can view their own record; viewing other users requires list_users capability. Fixes #64657
1 parent 8510818 commit e0d1214

1 file changed

Lines changed: 214 additions & 0 deletions

File tree

src/wp-includes/abilities.php

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,220 @@ function wp_register_core_abilities(): void {
196196
)
197197
);
198198

199+
wp_register_ability(
200+
'core/get-user',
201+
array(
202+
'label' => __( 'Get User' ),
203+
'description' => __( 'Retrieves profile data for a specific user by id, username, or email.' ),
204+
'category' => $category_user,
205+
'input_schema' => array(
206+
'type' => 'object',
207+
'oneOf' => array(
208+
array(
209+
'required' => array( 'id' ),
210+
),
211+
array(
212+
'required' => array( 'username' ),
213+
),
214+
array(
215+
'required' => array( 'email' ),
216+
),
217+
),
218+
'properties' => array(
219+
'id' => array(
220+
'type' => 'integer',
221+
'description' => __( 'The user ID to retrieve.' ),
222+
),
223+
'username' => array(
224+
'type' => 'string',
225+
'description' => __( 'The user login/username to retrieve.' ),
226+
),
227+
'email' => array(
228+
'type' => 'string',
229+
'description' => __( 'The user email address to retrieve.' ),
230+
),
231+
'include_capabilities' => array(
232+
'type' => 'boolean',
233+
'description' => __( 'Whether to include the user\'s capabilities in the response. Default is false.' ),
234+
'default' => false,
235+
),
236+
),
237+
'additionalProperties' => false,
238+
),
239+
'output_schema' => array(
240+
'type' => 'object',
241+
'required' => array( 'id', 'username', 'email', 'display_name', 'roles' ),
242+
'properties' => array(
243+
'id' => array(
244+
'type' => 'integer',
245+
'description' => __( 'The user ID.' ),
246+
),
247+
'username' => array(
248+
'type' => 'string',
249+
'description' => __( 'The user login/username.' ),
250+
),
251+
'email' => array(
252+
'type' => 'string',
253+
'description' => __( 'The user email address.' ),
254+
),
255+
'display_name' => array(
256+
'type' => 'string',
257+
'description' => __( 'The user\'s display name.' ),
258+
),
259+
'first_name' => array(
260+
'type' => 'string',
261+
'description' => __( 'The user\'s first name.' ),
262+
),
263+
'last_name' => array(
264+
'type' => 'string',
265+
'description' => __( 'The user\'s last name.' ),
266+
),
267+
'nickname' => array(
268+
'type' => 'string',
269+
'description' => __( 'The user\'s nickname.' ),
270+
),
271+
'description' => array(
272+
'type' => 'string',
273+
'description' => __( 'The user\'s biographical description.' ),
274+
),
275+
'url' => array(
276+
'type' => 'string',
277+
'description' => __( 'The user\'s website URL.' ),
278+
),
279+
'link' => array(
280+
'type' => 'string',
281+
'description' => __( 'The user\'s profile page URL.' ),
282+
),
283+
'slug' => array(
284+
'type' => 'string',
285+
'description' => __( 'The user\'s URL-friendly slug/nicename.' ),
286+
),
287+
'registered_date' => array(
288+
'type' => 'string',
289+
'format' => 'date-time',
290+
'description' => __( 'The date and time the user registered (ISO 8601 format).' ),
291+
),
292+
'roles' => array(
293+
'type' => 'array',
294+
'description' => __( 'The roles assigned to the user.' ),
295+
'items' => array(
296+
'type' => 'string',
297+
),
298+
),
299+
'locale' => array(
300+
'type' => 'string',
301+
'description' => __( 'The user\'s locale setting, such as en_US.' ),
302+
),
303+
'avatar_urls' => array(
304+
'type' => 'object',
305+
'description' => __( 'User avatar URLs at various sizes (24, 48, 96 pixels).' ),
306+
'properties' => array(
307+
'24' => array(
308+
'type' => 'string',
309+
'description' => __( 'Avatar URL at 24px size.' ),
310+
),
311+
'48' => array(
312+
'type' => 'string',
313+
'description' => __( 'Avatar URL at 48px size.' ),
314+
),
315+
'96' => array(
316+
'type' => 'string',
317+
'description' => __( 'Avatar URL at 96px size.' ),
318+
),
319+
),
320+
'additionalProperties' => false,
321+
),
322+
'capabilities' => array(
323+
'type' => 'object',
324+
'description' => __( 'The user\'s capabilities (only included if include_capabilities is true).' ),
325+
'additionalProperties' => array(
326+
'type' => 'boolean',
327+
),
328+
),
329+
),
330+
'additionalProperties' => false,
331+
),
332+
'execute_callback' => static function ( $input = array() ) {
333+
$user = null;
334+
if ( ! empty( $input['id'] ) ) {
335+
$user = get_user_by( 'id', $input['id'] );
336+
} elseif ( ! empty( $input['username'] ) ) {
337+
$user = get_user_by( 'login', $input['username'] );
338+
} elseif ( ! empty( $input['email'] ) ) {
339+
$user = get_user_by( 'email', $input['email'] );
340+
}
341+
342+
if ( ! $user || is_wp_error( $user ) ) {
343+
return new WP_Error(
344+
'user_not_found',
345+
__( 'The requested user does not exist.' )
346+
);
347+
}
348+
349+
$result = array(
350+
'id' => (int) $user->ID,
351+
'username' => $user->user_login,
352+
'email' => $user->user_email,
353+
'display_name' => $user->display_name,
354+
'first_name' => $user->first_name,
355+
'last_name' => $user->last_name,
356+
'nickname' => $user->nickname,
357+
'description' => $user->description,
358+
'url' => $user->user_url,
359+
'link' => get_author_posts_url( $user->ID ),
360+
'slug' => $user->user_nicename,
361+
'registered_date' => gmdate( 'c', strtotime( $user->user_registered ) ),
362+
'roles' => array_values( $user->roles ),
363+
'locale' => get_user_locale( $user ),
364+
'avatar_urls' => array(
365+
'24' => get_avatar_url( $user->ID, array( 'size' => 24 ) ),
366+
'48' => get_avatar_url( $user->ID, array( 'size' => 48 ) ),
367+
'96' => get_avatar_url( $user->ID, array( 'size' => 96 ) ),
368+
),
369+
);
370+
371+
if ( ! empty( $input['include_capabilities'] ) ) {
372+
$result['capabilities'] = $user->allcaps;
373+
}
374+
375+
return $result;
376+
},
377+
'permission_callback' => static function ( $input = array() ) {
378+
if ( ! is_user_logged_in() ) {
379+
return false;
380+
}
381+
382+
$target_user = null;
383+
if ( ! empty( $input['id'] ) ) {
384+
$target_user = get_user_by( 'id', $input['id'] );
385+
} elseif ( ! empty( $input['username'] ) ) {
386+
$target_user = get_user_by( 'login', $input['username'] );
387+
} elseif ( ! empty( $input['email'] ) ) {
388+
$target_user = get_user_by( 'email', $input['email'] );
389+
}
390+
391+
if ( ! $target_user || is_wp_error( $target_user ) ) {
392+
return true;
393+
}
394+
395+
$current_user = wp_get_current_user();
396+
if ( (int) $target_user->ID === (int) $current_user->ID ) {
397+
return true;
398+
}
399+
400+
return current_user_can( 'list_users' );
401+
},
402+
'meta' => array(
403+
'annotations' => array(
404+
'readonly' => true,
405+
'destructive' => false,
406+
'idempotent' => true,
407+
),
408+
'show_in_rest' => true,
409+
),
410+
)
411+
);
412+
199413
wp_register_ability(
200414
'core/get-environment-info',
201415
array(

0 commit comments

Comments
 (0)