PluginProbe
wpForo Forum / 3.0.9
wpForo Forum v3.0.9
3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 All 137 releases
wpforo / classes / AIUserTrait.php

AIUserTrait.php in wpForo Forum 3.0.9, at classes/AIUserTrait.php

221 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace wpforo\classes;
4
5 /**
6 * wpForo AI User Enrichment Trait
7 *
8 * Provides unified user data enrichment methods for AI classes.
9 * Handles batch fetching of user display names with proper fallback chains.
10 *
11 * @since 3.0.0
12 */
13 trait AIUserTrait {
14
15 /**
16 * User type constants (if not defined in using class)
17 */
18 private static $USER_TYPE_USER = 'user';
19 private static $USER_TYPE_GUEST = 'guest';
20 private static $USER_TYPE_CRON = 'cron';
21 private static $USER_TYPE_SYSTEM = 'system';
22
23 /**
24 * Enrich items with user display names
25 *
26 * Batch fetches user data and adds 'user_display' field to each item.
27 * Uses proper fallback chain: display_name → user_nicename → user_login → Guest
28 *
29 * @param array $items Array of items with user IDs
30 * @param string $userid_field Field name containing user ID (default: 'userid')
31 * @param array $options Options:
32 * - 'user_type_field' => field for user type (default: 'user_type')
33 * - 'output_field' => field name for display name (default: 'user_display')
34 * - 'use_type_labels' => use type labels for non-users (default: true)
35 *
36 * @return array Enriched items with user_display field
37 */
38 protected function enrich_items_with_user_data( array $items, string $userid_field = 'userid', array $options = [] ): array {
39 if ( empty( $items ) ) {
40 return $items;
41 }
42
43 $defaults = [
44 'user_type_field' => 'user_type',
45 'output_field' => 'user_display',
46 'use_type_labels' => true,
47 ];
48 $options = array_merge( $defaults, $options );
49
50 // Collect unique user IDs (excluding 0 and empty)
51 $user_ids = [];
52 foreach ( $items as $item ) {
53 $userid = isset( $item[ $userid_field ] ) ? (int) $item[ $userid_field ] : 0;
54 if ( $userid > 0 ) {
55 $user_ids[ $userid ] = $userid;
56 }
57 }
58
59 // Batch fetch users using wpForo's cached method (single query)
60 $user_names = [];
61 if ( ! empty( $user_ids ) ) {
62 $members = WPF()->member->get_members( [ 'include' => array_values( $user_ids ) ] );
63 foreach ( $members as $member ) {
64 $user_names[ $member['userid'] ] = $this->get_display_name_with_fallback( $member );
65 }
66 }
67
68 // Enrich items
69 foreach ( $items as &$item ) {
70 $userid = isset( $item[ $userid_field ] ) ? (int) $item[ $userid_field ] : 0;
71 $user_type = $item[ $options['user_type_field'] ] ?? self::$USER_TYPE_USER;
72
73 if ( $userid > 0 && isset( $user_names[ $userid ] ) ) {
74 $item[ $options['output_field'] ] = $user_names[ $userid ];
75 // Ensure user_type is set for registered users
76 if ( ! isset( $item[ $options['user_type_field'] ] ) ) {
77 $item[ $options['user_type_field'] ] = self::$USER_TYPE_USER;
78 }
79 } else {
80 // No valid user ID or user not found
81 if ( $options['use_type_labels'] && ! empty( $user_type ) && $user_type !== self::$USER_TYPE_USER ) {
82 $item[ $options['output_field'] ] = $this->get_user_type_display_label( $user_type );
83 } else {
84 $item[ $options['output_field'] ] = wpforo_phrase( 'Guest', false );
85 }
86 // Set guest type if not already set
87 if ( ! isset( $item[ $options['user_type_field'] ] ) || $item[ $options['user_type_field'] ] === self::$USER_TYPE_USER ) {
88 $item[ $options['user_type_field'] ] = self::$USER_TYPE_GUEST;
89 }
90 }
91 }
92
93 return $items;
94 }
95
96 /**
97 * Get display name for a single user ID
98 *
99 * Uses wpforo_member() for cached single-user lookup with fallback chain.
100 *
101 * @param int $userid User ID (0 for guests)
102 *
103 * @return string User display name
104 */
105 protected function get_single_user_display_name( int $userid ): string {
106 $userid = (int) $userid;
107
108 // For guests (userid = 0), return translated Guest
109 if ( $userid === 0 ) {
110 return wpforo_phrase( 'Guest', false );
111 }
112
113 // Get member data using wpforo_member (uses caching)
114 $member = wpforo_member( $userid );
115
116 if ( empty( $member ) || empty( $member['userid'] ) ) {
117 return wpforo_phrase( 'Guest', false );
118 }
119
120 return $this->get_display_name_with_fallback( $member );
121 }
122
123 /**
124 * Get display name with fallback chain
125 *
126 * Tries: display_name → user_nicename → user_login → Guest
127 *
128 * @param array $member Member data array
129 *
130 * @return string Display name
131 */
132 protected function get_display_name_with_fallback( array $member ): string {
133 // Try display_name first
134 if ( ! empty( $member['display_name'] ) && ! $this->is_anonymous_name( $member['display_name'] ) ) {
135 return $member['display_name'];
136 }
137
138 // Try user_nicename
139 if ( ! empty( $member['user_nicename'] ) && ! $this->is_anonymous_name( $member['user_nicename'] ) ) {
140 return $member['user_nicename'];
141 }
142
143 // Try user_login
144 if ( ! empty( $member['user_login'] ) && ! $this->is_anonymous_name( $member['user_login'] ) ) {
145 return $member['user_login'];
146 }
147
148 // Final fallback
149 return wpforo_phrase( 'Guest', false );
150 }
151
152 /**
153 * Check if name is a placeholder/anonymous name
154 *
155 * @param string $name Name to check
156 *
157 * @return bool True if name appears to be anonymous/placeholder
158 */
159 private function is_anonymous_name( string $name ): bool {
160 $lower = strtolower( trim( $name ) );
161
162 return in_array( $lower, [ 'anonymous', 'guest', '' ], true );
163 }
164
165 /**
166 * Get user type display label
167 *
168 * Returns translated labels for special user types (cron, system, guest).
169 *
170 * @param string $user_type User type constant
171 *
172 * @return string Display label
173 */
174 protected function get_user_type_display_label( string $user_type ): string {
175 $labels = [
176 self::$USER_TYPE_USER => wpforo_phrase( 'User', false ),
177 self::$USER_TYPE_GUEST => wpforo_phrase( 'Guest', false ),
178 self::$USER_TYPE_CRON => wpforo_phrase( 'Cron Job', false ),
179 self::$USER_TYPE_SYSTEM => wpforo_phrase( 'System', false ),
180 ];
181
182 // Check if using class has its own constants
183 if ( defined( 'static::USER_TYPE_USER' ) ) {
184 $labels = [
185 static::USER_TYPE_USER => wpforo_phrase( 'User', false ),
186 static::USER_TYPE_GUEST => wpforo_phrase( 'Guest', false ),
187 static::USER_TYPE_CRON => wpforo_phrase( 'Cron Job', false ),
188 static::USER_TYPE_SYSTEM => wpforo_phrase( 'System', false ),
189 ];
190 }
191
192 return $labels[ $user_type ] ?? $user_type;
193 }
194
195 /**
196 * Batch get display names for multiple user IDs
197 *
198 * Returns an associative array mapping user IDs to display names.
199 *
200 * @param array $user_ids Array of user IDs
201 *
202 * @return array Associative array [userid => display_name]
203 */
204 protected function batch_get_user_display_names( array $user_ids ): array {
205 $user_ids = array_unique( array_filter( array_map( 'intval', $user_ids ) ) );
206
207 if ( empty( $user_ids ) ) {
208 return [];
209 }
210
211 $user_names = [];
212 $members = WPF()->member->get_members( [ 'include' => array_values( $user_ids ) ] );
213
214 foreach ( $members as $member ) {
215 $user_names[ $member['userid'] ] = $this->get_display_name_with_fallback( $member );
216 }
217
218 return $user_names;
219 }
220 }
221