Show instructor real name or nickname in group-class views, not the login
CI / Tests (PHP 8.2) (pull_request) Successful in 46s
CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m47s
CI / Coding Standards (pull_request) Successful in 2m51s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m41s
CI / Build Plugin Zip (pull_request) Skipped

Add Auth\UserName::format(), which prefers a user's first + last name, then
their nickname, avoiding display_name (which can be the login/username).
Route the instructor name through it in both the front-end offerings response
(instructor_name) and the back-end group-class summary and details views.

Tests: composer test (513), composer lint, composer cs all pass.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
2026-07-23 17:50:34 -03:00
co-authored by Claude Opus 4.8
parent b066bef353
commit 87cfe921a9
8 changed files with 136 additions and 20 deletions
+35
View File
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Unsupervised\Schedular\Auth;
/**
* Resolves a person's public-facing name for display. Prefers their real name
* (first + last), then their nickname — deliberately avoiding the account's
* login/username, which `display_name` can otherwise expose.
*/
class UserName {
/**
* The display name for a user: "First Last" when a real name is set,
* otherwise the WordPress nickname. Falls back to the numeric id (or an empty
* string when none is given) when the user cannot be loaded or has no name.
*/
public static function format( ?\WP_User $user, int $fallbackId = 0 ): string {
if ( ! $user instanceof \WP_User ) {
return $fallbackId > 0 ? (string) $fallbackId : '';
}
$full = trim( $user->first_name . ' ' . $user->last_name );
if ( '' !== $full ) {
return $full;
}
$nickname = trim( $user->nickname );
if ( '' !== $nickname ) {
return $nickname;
}
return $fallbackId > 0 ? (string) $fallbackId : '';
}
}
+14 -6
View File
@@ -8,6 +8,7 @@ use Unsupervised\Schedular\Auth\InviteRepository;
use Unsupervised\Schedular\Auth\RegistrationController;
use Unsupervised\Schedular\Auth\RegistrationMailer;
use Unsupervised\Schedular\Auth\RoleManager;
use Unsupervised\Schedular\Auth\UserName;
use Unsupervised\Schedular\Offering\Offering;
use Unsupervised\Schedular\Offering\OfferingRepository;
use Unsupervised\Schedular\Payment\Payment;
@@ -73,12 +74,10 @@ class GroupClassController {
$rows = array_map(
function ( Offering $offering ): array {
$instructor = get_userdata( $offering->instructorId );
return [
'id' => $offering->id,
'title' => $offering->title,
'instructor' => $instructor ? $instructor->display_name : (string) $offering->instructorId,
'instructor' => $this->instructorName( $offering ),
'when' => $this->whenLabel( $offering ),
'capacity' => $offering->capacity,
'enrolled' => $this->enrollments->countActiveForOffering( (int) $offering->id ),
@@ -196,10 +195,8 @@ class GroupClassController {
];
}
$instructor = get_userdata( $offering->instructorId );
return $this->classSummary( $offering, $enrollments ) + [
'instructor' => $instructor ? $instructor->display_name : (string) $offering->instructorId,
'instructor' => $this->instructorName( $offering ),
'price' => $offering->price,
'currency' => $offering->currency,
'duration' => $offering->durationMinutes,
@@ -211,6 +208,17 @@ class GroupClassController {
];
}
/**
* The teaching instructor's display name — their real name or nickname, never
* the login. Falls back to the numeric id when the account is gone. See
* {@see UserName::format()}.
*/
private function instructorName( Offering $offering ): string {
$user = get_userdata( $offering->instructorId );
return UserName::format( $user instanceof \WP_User ? $user : null, $offering->instructorId );
}
/**
* Human-readable "when" label for a class: the class date (or weekly date
* range) and, when set, the start time. Empty when the class has no date.
+5 -3
View File
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Unsupervised\Schedular\Offering;
use Unsupervised\Schedular\Auth\RoleManager;
use Unsupervised\Schedular\Auth\UserName;
use Unsupervised\Schedular\GroupClass\GroupAccessRepository;
use Unsupervised\Schedular\Val;
@@ -84,8 +85,9 @@ class OfferingEndpoint {
}
/**
* A public-facing offering array with the assigned instructor's display name
* added (empty when the instructor account no longer exists).
* A public-facing offering array with the assigned instructor's name added —
* their real name or nickname, never the login (empty when the instructor
* account no longer exists). See {@see UserName::format()}.
*
* @return array<string, mixed>
*/
@@ -93,7 +95,7 @@ class OfferingEndpoint {
$out = $offering->toArray( includeEtransferEmail: false );
$user = get_userdata( $offering->instructorId );
$out['instructor_name'] = $user instanceof \WP_User ? $user->display_name : '';
$out['instructor_name'] = UserName::format( $user instanceof \WP_User ? $user : null );
return $out;
}