PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.10.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.10.0
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
← All changes | app/Models/User.php +84 -46 2.7.02.10.0 View file →
@@ -18,8 +18,22 @@
18 18 *
19 19 * @package FluentCommunity\App\Models
20 20 *
21 21 * @version 1.0.0
22 + *
23 + * @property int $ID
24 + * @property string $user_login
25 + * @property string $user_pass
26 + * @property string $user_nicename
27 + * @property string $user_email
28 + * @property string $user_url
29 + * @property string $user_registered
30 + * @property string $user_activation_key
31 + * @property int $user_status
32 + * @property string $display_name
33 + * @property-read string $photo
34 + * @property-read XProfile|null $xprofile
35 + * @property string|null $username
22 36 */
23 37 class User extends Model
24 38 {
25 39 protected $table = 'users';
@@ -25,17 +39,17 @@
25 39 protected $table = 'users';
26 40
27 41 protected $primaryKey = 'ID';
28 42
29 - protected $hidden = ['user_pass', 'user_activation_key'];
43 + protected $hidden = [ 'user_pass', 'user_activation_key' ];
30 44
31 - protected $appends = ['photo'];
45 + protected $appends = [ 'photo' ];
32 46
33 47 public $timestamps = false;
34 48
35 49 protected $searchable = [
36 50 'display_name',
37 - 'user_email'
51 + 'user_email',
38 52 ];
39 53
40 54 public function scopeSearchBy($query, $search)
41 55 {
@@ -56,9 +70,9 @@
56 70 {
57 71 if ($search) {
58 72 $fields = [
59 73 'display_name',
60 - 'user_login'
74 + 'user_login',
61 75 ];
62 76 $query->where(function ($query) use ($fields, $search) {
63 77 $query->where(array_shift($fields), 'LIKE', "$search%");
64 78 foreach ($fields as $field) {
@@ -75,13 +89,13 @@
75 89 * @return string
76 90 */
77 91 public function getPhotoAttribute()
78 92 {
79 - if ($photo = get_user_meta($this->ID, '_fcom_user_photo', true)) {
93 + if ($photo = get_user_meta($this->ID, '_fcom_user_photo', true)) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
80 94 return $photo;
81 95 }
82 96
83 - if ($contact = $this->getContact()) {
97 + if ($contact = $this->getContact()) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
84 98 return $contact->photo;
85 99 }
86 100
87 101 if (empty($this->attributes['user_email'])) {
@@ -93,9 +107,9 @@
93 107 }
94 108 return '';
95 109 }
96 110
97 - if (Utility::getPrivacySetting('enable_gravatar') != 'yes') {
111 + if (Utility::getPrivacySetting('enable_gravatar') == 'no') {
98 112 return apply_filters('fluent_community/default_avatar', FLUENT_COMMUNITY_PLUGIN_URL . 'assets/images/placeholder.png', $this->ID);
99 113 }
100 114
101 115 $hash = md5(strtolower(trim($this->attributes['user_email'])));
@@ -194,9 +208,9 @@
194 208 'user_id' => $user->ID,
195 209 'created_at' => $user->user_registered,
196 210 'photo' => $this->photo,
197 211 'username' => $this->username,
198 - 'is_verified' => $this->isVerified()
212 + 'is_verified' => $this->isVerified(),
199 213 ];
200 214 }
201 215
202 216 public function spaces()
@@ -201,22 +215,35 @@
201 215
202 216 public function spaces()
203 217 {
204 218 return $this->belongsToMany(BaseSpace::class, 'fcom_space_user', 'user_id', 'space_id')
205 - ->withPivot(['role', 'status', 'created_at']);
219 + ->withPivot([ 'role', 'status', 'created_at' ]);
206 220 }
207 221
208 222 public function courses()
209 223 {
210 224 return $this->belongsToMany(Course::class, 'fcom_space_user', 'user_id', 'space_id')
211 - ->withPivot(['role', 'created_at']);
225 + ->withPivot([ 'role', 'created_at' ]);
212 226 }
213 227
228 + /**
229 + * @deprecated 2.8.2 Use notificationPreferences() - preferences no longer live
230 + * in fcom_notification_users.
231 + */
214 232 public function notificationSubscriptions()
215 233 {
216 234 return $this->hasMany(NotificationSubscription::class, 'user_id');
217 235 }
218 236
237 + /**
238 + * Explicit notification preference overrides across every channel.
239 + * Recipient selection for email fan-outs is driven off this relation.
240 + */
241 + public function notificationPreferences()
242 + {
243 + return $this->hasMany(NotificationPreference::class, 'user_id', 'ID');
244 + }
245 +
219 246 public function space_pivot()
220 247 {
221 248 return $this->belongsTo(SpaceUserPivot::class, 'ID', 'user_id')->withoutGlobalScopes();
222 249 }
@@ -233,8 +260,9 @@
233 260
234 261 public function community_role()
235 262 {
236 263 return $this->belongsTo(Meta::class, 'ID', 'object_id')
264 + ->where('object_type', 'user')
237 265 ->where('meta_key', '_user_community_roles');
238 266 }
239 267
240 268 public function updateCustomData($updateData, $removeSrc = false)
@@ -248,17 +276,17 @@
248 276 'last_name' => $lastName,
249 277 'display_name' => trim($firstName . ' ' . $lastName),
250 278 'description' => isset($updateData['short_description']) ? sanitize_textarea_field($updateData['short_description']) : '',
251 279 'user_url' => isset($updateData['website']) ? esc_url($updateData['website']) : '',
252 - 'ID' => $this->ID
280 + 'ID' => $this->ID,
253 281 ];
254 282
255 283 wp_update_user($userData);
256 284
257 - if ($contact = $this->getContact()) {
285 + if ($contact = $this->getContact()) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
258 286 $contact->fill(array_filter([
259 287 'first_name' => $firstName,
260 - 'last_name' => $lastName
288 + 'last_name' => $lastName,
261 289 ]));
262 290
263 291 $dirtyFields = $contact->getDirty();
264 292 if ($dirtyFields) {
@@ -271,8 +299,9 @@
271 299
272 300 return $this;
273 301 }
274 302
303 + // WP account real name (first + last, falling back to wp_users.display_name). Not the public community name — use getPublicDisplayName() for anything shown to other members.
275 304 public function getDisplayName()
276 305 {
277 306 $user = get_user_by('ID', $this->ID);
278 307 $name = '';
@@ -285,8 +314,19 @@
285 314
286 315 return $user->display_name;
287 316 }
288 317
318 + // Public community name (xprofile.display_name, falling back to wp_users.display_name). Use this for actor names in notifications/emails to avoid leaking the legal name.
319 + public function getPublicDisplayName()
320 + {
321 + $name = $this->xprofile ? $this->xprofile->display_name : '';
322 + if (!$name) {
323 + $name = $this->display_name;
324 + }
325 +
326 + return apply_filters('fluent_community/public_display_name', $name, $this);
327 + }
328 +
289 329 public function getCustomMeta($key, $default = null)
290 330 {
291 331 $exist = Meta::where('object_type', 'user')
292 332 ->where('object_id', $this->ID)
@@ -316,9 +356,9 @@
316 356 return Meta::create([
317 357 'object_type' => 'user',
318 358 'object_id' => $this->ID,
319 359 'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
320 - 'value' => $value
360 + 'value' => $value,
321 361 ]);
322 362 }
323 363
324 364 public function isNotMemberOfAnySpace()
@@ -344,9 +384,9 @@
344 384 public function getJoinedSpaceIds()
345 385 {
346 386 $globalRoles = $this->getCommunityRoles();
347 387
348 - if (array_intersect($globalRoles, ['admin', 'moderator'])) {
388 + if (array_intersect($globalRoles, [ 'admin', 'moderator' ])) {
349 389 return BaseSpace::onlyMain()->pluck('id')->toArray();
350 390 }
351 391
352 392 return BaseSpace::onlyMain()->whereHas('members', function ($query) {
@@ -357,9 +397,9 @@
357 397
358 398 public function getCommunityRoles()
359 399 {
360 400 if (Helper::isSuperAdmin($this->ID)) {
361 - return ['admin'];
401 + return [ 'admin' ];
362 402 }
363 403
364 404 return (array)$this->getCustomMeta('_user_community_roles', []);
365 405 }
@@ -370,9 +410,9 @@
370 410 }
371 411
372 412 public function isCommunityModerator()
373 413 {
374 - return !!array_intersect(['moderator', 'admin'], $this->getCommunityRoles());
414 + return (bool)array_intersect([ 'moderator', 'admin' ], $this->getCommunityRoles());
375 415 }
376 416
377 417 public function hasCommunityModeratorAccess()
378 418 {
@@ -403,9 +443,9 @@
403 443 public function hasSpaceManageAccess()
404 444 {
405 445 $permissions = array_filter($this->getPermissions(true));
406 446
407 - return !!array_intersect(['community_admin', 'course_admin'], array_keys($permissions));
447 + return (bool)array_intersect([ 'community_admin', 'course_admin' ], array_keys($permissions));
408 448 }
409 449
410 450 public function getSpaceRole($space)
411 451 {
@@ -447,9 +487,9 @@
447 487 public function cacheAccessSpaces()
448 488 {
449 489 $globalRoles = $this->getCommunityRoles();
450 490
451 - if (array_intersect($globalRoles, ['admin', 'moderator'])) {
491 + if (array_intersect($globalRoles, [ 'admin', 'moderator' ])) {
452 492 $spaces = BaseSpace::onlyMain()->get();
453 493 } else {
454 494 $spaces = BaseSpace::onlyMain()->where(function ($spaceQuery) {
455 495 $spaceQuery->whereHas('members', function ($memberQuery) {
@@ -469,14 +509,14 @@
469 509 protected function getRolePermissions($roles)
470 510 {
471 511 if (!$roles) {
472 512 return apply_filters('fluent_community/user/permissions', [
473 - 'read' => true
513 + 'read' => true,
474 514 ], $roles, $this);
475 515 }
476 516
477 517 $isAdmin = in_array('admin', $roles);
478 - $isModerator = !!array_intersect($roles, ['admin', 'moderator']);
518 + $isModerator = (bool)array_intersect($roles, [ 'admin', 'moderator' ]);
479 519
480 520 $permissions = [
481 521 'admin' => $isAdmin,
482 522 'super_admin' => Helper::isSuperAdmin(),
@@ -485,15 +525,15 @@
485 525 'delete_any_feed' => $isModerator,
486 526 'edit_any_feed' => $isModerator,
487 527 'delete_any_comment' => $isModerator,
488 528 'edit_any_comment' => $isModerator,
489 - 'read' => true
529 + 'read' => true,
490 530 ];
491 531
492 532 if ($isAdmin || in_array('course_admin', $roles)) {
493 533 $permissions['course_creator'] = true;
494 534 $permissions['course_admin'] = true;
495 - } else if (in_array('course_creator', $roles)) {
535 + } elseif (in_array('course_creator', $roles)) {
496 536 $permissions['course_creator'] = true;
497 537 }
498 538
499 539 return apply_filters('fluent_community/user/permissions', $permissions, $roles, $this);
@@ -500,19 +540,17 @@
500 540 }
501 541
502 542 public function getPermissions($cached = true)
503 543 {
504 - static $permissions;
544 + static $permissions = [];
505 545
506 - if ($permissions && $cached) {
507 - return $permissions;
546 + if ($cached && isset($permissions[$this->ID])) {
547 + return $permissions[$this->ID];
508 548 }
509 549
510 550 $roles = $this->getCommunityRoles();
511 551
512 - $permissions = $this->getRolePermissions($roles);
513 -
514 - return $permissions;
552 + return $permissions[$this->ID] = $this->getRolePermissions($roles);
515 553 }
516 554
517 555 public function getSpacePermissions($space)
518 556 {
@@ -525,8 +563,9 @@
525 563 $hasDocuments = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'document_library') == 'yes';
526 564 $hasMediaGallery = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'media_gallery') == 'yes';
527 565
528 566 $isRestrictedPost = Arr::get($space->settings, 'restricted_post_only') == 'yes';
567 + $isVerifiedPostOnly = Arr::get($space->settings, 'verified_post_only') == 'yes';
529 568
530 569 $documentAccess = Arr::get($space->settings, 'document_access');
531 570 $mediaAccess = Arr::get($space->settings, 'media_access');
532 571
@@ -539,10 +578,10 @@
539 578 'can_view_members' => $space->canViewMembers($this),
540 579 'is_pending' => false,
541 580 'is_non_member' => true,
542 581 'can_view_info' => $space->privacy !== 'secret',
543 - 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in']),
544 - 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, ['everybody', 'logged_in'])
582 + 'can_view_documents' => $hasDocuments && in_array($documentAccess, [ 'everybody', 'logged_in' ]),
583 + 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, [ 'everybody', 'logged_in' ]),
545 584 ];
546 585
547 586 if ($space->privacy === 'secret' || $space->privacy === 'private') {
548 587 $permissions['can_view_posts'] = false;
@@ -549,9 +588,9 @@
549 588 $permissions['can_view_members'] = false;
550 589 $permissions['can_view_documents'] = false;
551 590 $permissions['can_view_media'] = false;
552 591 }
553 - } else if ($role == 'pending') {
592 + } elseif ($role == 'pending') {
554 593 $permissions = [
555 594 'can_create_post' => false,
556 595 'registered' => true,
557 596 'can_view_posts' => true,
@@ -558,10 +597,10 @@
558 597 'can_comment' => false,
559 598 'can_view_members' => $space->canViewMembers($this),
560 599 'is_pending' => true,
561 600 'can_view_info' => $space->privacy !== 'secret',
562 - 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in']),
563 - 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, ['everybody', 'logged_in'])
601 + 'can_view_documents' => $hasDocuments && in_array($documentAccess, [ 'everybody', 'logged_in' ]),
602 + 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, [ 'everybody', 'logged_in' ]),
564 603 ];
565 604
566 605 if ($space->privacy === 'secret' || $space->privacy === 'private') {
567 606 $permissions['can_view_posts'] = false;
@@ -568,11 +607,11 @@
568 607 $permissions['can_view_members'] = false;
569 608 $permissions['can_view_documents'] = false;
570 609 $permissions['can_view_media'] = false;
571 610 }
572 - } else if ($role == 'member' || $role == 'student') {
611 + } elseif ($role == 'member' || $role == 'student') {
573 612 $permissions = [
574 - 'can_create_post' => $isRestrictedPost ? false : true,
613 + 'can_create_post' => $isRestrictedPost ? false : (!$isVerifiedPostOnly || $this->isVerified()),
575 614 'registered' => true,
576 615 'can_view_posts' => true,
577 616 'can_view_members' => $space->canViewMembers($this),
578 617 'can_comment' => true,
@@ -578,12 +617,12 @@
578 617 'can_comment' => true,
579 618 'can_view_info' => true,
580 619 'can_view_documents' => $hasDocuments,
581 620 'can_upload_documents' => $hasDocuments && Arr::get($space->settings, 'document_upload') == 'members_only',
582 - 'can_view_media' => $hasMediaGallery
621 + 'can_view_media' => $hasMediaGallery,
583 622 ];
584 623 } else {
585 - $isMod = in_array($role, ['admin', 'moderator']);
624 + $isMod = in_array($role, [ 'admin', 'moderator' ]);
586 625 $isAdmin = $role === 'admin';
587 626 $permissions = [
588 627 'can_create_post' => $isRestrictedPost ? $isMod : true,
589 628 'can_view_posts' => true,
@@ -602,13 +641,13 @@
602 641 'can_comment' => $isMod,
603 642 'can_view_info' => true,
604 643 'can_view_documents' => $hasDocuments,
605 644 'can_upload_documents' => $hasDocuments && $isMod,
606 - 'can_view_media' => $hasMediaGallery
645 + 'can_view_media' => $hasMediaGallery,
607 646 ];
608 647 }
609 648
610 - $permissions['is_member'] = in_array($role, ['admin', 'moderator', 'member', 'student']);
649 + $permissions['is_member'] = in_array($role, [ 'admin', 'moderator', 'member', 'student' ]);
611 650
612 651 return apply_filters('fluent_community/user/space/permissions', $permissions, $space, $role, $this);
613 652 }
614 653
@@ -733,18 +772,17 @@
733 772 'short_description' => get_user_meta($this->ID, 'description', true),
734 773 'meta' => [
735 774 'website' => $this->user_url,
736 775 'cover_photo' => get_user_meta($this->ID, '_fluent_cover_photo', true),
737 - 'short_description_rendered' => wp_kses_post(FeedsHelper::mdToHtml(get_user_meta($this->ID, 'description', true)))
738 - ]
776 + 'short_description_rendered' => wp_kses_post(FeedsHelper::mdToHtml(get_user_meta($this->ID, 'description', true))),
777 + ],
739 778 ];
740 779
741 780 if ($exist) {
742 - unset($data['avatar']);
743 - unset($data['username']);
781 + $data = array_diff_key($data, [ 'avatar' => true, 'username' => true ]);
744 782
745 783 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
746 - $data['created_at'] = $this->user_registered;
784 + $data['created_at'] = get_date_from_gmt($this->user_registered, 'Y-m-d H:i:s');
747 785 }
748 786
749 787 $data['meta'] = wp_parse_args($exist->meta, $data['meta']);
750 788 $exist->fill($data);
@@ -755,9 +793,9 @@
755 793 $counter = 1;
756 794 $initialUserName = $data['username'];
757 795 while (XProfile::where('username', $initialUserName)->first()) {
758 796 $initialUserName = $data['username'] . '_' . $counter;
759 - $counter++;
797 + ++$counter;
760 798 }
761 799
762 800 $data['username'] = $initialUserName;
763 801 $data['status'] = 'active';