Users
Wirechat uses your application's user model for panel access, feature access, profile display, unread counts, conversation membership, and user search.
User-model methods control how Wirechat renders panels, starts conversations, displays users, and searches for recipients.
Choosing The User Model
In these docs, user model means the Eloquent model that should participate in Wirechat. It does not have to be App\Models\User.
You can use App\Models\Admin, App\Models\Customer, App\Models\Member, or another authenticatable model that should access panels, appear in search, join conversations, and use chat features.
Register that model with models.user:
// config/wirechat.php
'models' => [
'user' => \App\Models\Admin::class,
],
The configured model should implement WirechatUser and use InteractsWithWirechat, just like the examples below.
User Access
Define access methods on your configured Wirechat user model. In a default Laravel app this is usually app/Models/User.php. Method snippets without a class wrapper belong on that model unless a panel provider is shown.
Panel Access
Wirechat calls canAccessWirechatPanel() when a user opens a panel route. Return false to deny access to that panel.
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Wirechat\Wirechat\Contracts\WirechatUser;
use Wirechat\Wirechat\Panel;
use Wirechat\Wirechat\Traits\InteractsWithWirechat;
class User extends Authenticatable implements WirechatUser
{
use InteractsWithWirechat;
// ...
public function canAccessWirechatPanel(Panel $panel): bool
{
return $this->hasVerifiedEmail();
}
}
Because the current $panel is available, you can apply different rules per panel:
public function canAccessWirechatPanel(Panel $panel): bool
{
if ($panel->getId() === 'admin') {
return $this->is_admin && $this->hasVerifiedEmail();
}
return true;
}
Controlling 1-to-1 Chat Creation
On the same user model, canCreateChats() controls whether the authenticated user can start one-to-one conversations through Wirechat's built-in UI.
public function canCreateChats(): bool
{
return $this->hasVerifiedEmail();
}
The method can return any application rule:
public function canCreateChats(): bool
{
if ($this->conversations()->count() >= 100) {
return false;
}
if ($this->created_at->gt(now()->subDay())) {
return false;
}
return $this->hasVerifiedEmail();
}
When this method returns false, Wirechat hides the New Chat action and blocks UI-based chat creation. Existing conversations remain accessible.
If your app calls createConversationWith() directly, apply your own check around that call.
Controlling Group Creation
On the same user model, canCreateGroups() controls whether the authenticated user can create group conversations through Wirechat's built-in UI.
public function canCreateGroups(): bool
{
return $this->subscription?->active === true;
}
Combine it with verification, roles, account age, or any other application rule:
public function canCreateGroups(): bool
{
return $this->hasVerifiedEmail()
&& ($this->is_premium || $this->hasRole('admin'));
}
public function canCreateGroups(): bool
{
return $this->reputation_score >= 50
&& $this->account_age_days >= 30;
}
When this method returns false, Wirechat hides the New Group action and blocks UI-based group creation. The user can still participate in groups they already belong to.
If your app calls createGroup() directly, apply your own check around that call.
Controlling Who Can Message Whom
The canSendMessageTo(Model $recipient) method controls whether a user may send messages or message requests to a specific recipient.
Wirechat checks this method in the UI and when calling sendMessageRequestTo(), createConversationWith(), and sendMessage().
Wirechat's default implementation returns true. Define the method on your user model when private messages need blocking, friendship checks, or another application-specific access rule.
use Illuminate\Database\Eloquent\Model;
public function canSendMessageTo(Model $recipient): bool
{
return ! $this->hasBlocked($recipient)
&& ! $recipient->hasBlocked($this);
}
use Illuminate\Database\Eloquent\Model;
public function canSendMessageTo(Model $recipient): bool
{
return $this->friends()
->where('friend_id', $recipient->getKey())
->exists();
}
When this method returns false, Wirechat rejects private message creation and sending with a 403 response.
Unread Counts
User models using InteractsWithWirechat can retrieve unread message totals across all conversations:
$user->getUnreadCount();
Pass a conversation to scope the unread count to one thread:
$conversation = $user->conversations()->first();
$user->getUnreadCount($conversation);
Attributes
User attributes define how names, avatars, and profile links appear throughout chats.
User’s Name
By default, Wirechat uses the name attribute from your User model. Define getWirechatNameAttribute() on the user model to return a different display name:
use Wirechat\Wirechat\Traits\InteractsWithWirechat;
use Wirechat\Wirechat\Contracts\WirechatUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements WirechatUser
{
use InteractsWithWirechat;
public function getWirechatNameAttribute(): string
{
return $this->display_name ?? $this->name;
}
}
User Subtitle
Use getWirechatSubtitleAttribute() for a short line shown under the user's name in user search results, member rows, requests, and chat info:
use Wirechat\Wirechat\Traits\InteractsWithWirechat;
use Wirechat\Wirechat\Contracts\WirechatUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements WirechatUser
{
use InteractsWithWirechat;
public function getWirechatSubtitleAttribute(): ?string
{
return $this->headline;
}
}
The subtitle is optional. When it returns null, Wirechat leaves the secondary line hidden.
Avatar URL
Set the URL that should be used for the user’s avatar across chats, member lists, and chat info:
namespace App\Models;
use Wirechat\Wirechat\Traits\InteractsWithWirechat;
use Wirechat\Wirechat\Contracts\WirechatUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements WirechatUser
{
use InteractsWithWirechat;
public function getWirechatAvatarUrlAttribute(): string
{
return $this->avatar_url ?? asset('images/default-avatar.png');
}
}
Profile URL
When a user's name or avatar is clicked, Wirechat uses getWirechatProfileUrlAttribute() on the user model to determine where to redirect:
use Wirechat\Wirechat\Traits\InteractsWithWirechat;
use Wirechat\Wirechat\Contracts\WirechatUser;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements WirechatUser
{
use InteractsWithWirechat;
public function getWirechatProfileUrlAttribute(): string
{
return route('profile.show', $this->id);
}
}
Searching Users
Wirechat searches users when someone starts a new conversation or adds members to a group.
By default, Wirechat searches the configured attributes on your User model. Panel-level callbacks can replace that query when your application needs stricter filtering.
Customizing Searchable Attributes
Without a custom callback, Wirechat searches your User model using the attributes configured on the panel:
use Wirechat\Wirechat\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->searchableAttributes(['name', 'email', 'username']);
}
In this example, a query like "john" will match users where the name, email, or username contains "john".
Subtitle display is separate from search matching. Add the backing database column to searchableAttributes() when the subtitle should be searchable, or use searchUsersUsing() for derived accessor values.
Customizing the Search
For full control over recipient search, define a searchUsersUsing() callback on the panel. Return WirechatUserResource results so Livewire and API responses keep the same shape:
use Wirechat\Wirechat\Panel;
use Wirechat\Wirechat\Http\Resources\WirechatUserResource;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->searchUsersUsing(function (string $needle) {
return WirechatUserResource::collection(
\App\Models\User::query()
->where('is_active', true)
->where('name', 'like', "%{$needle}%")
->limit(20)
->get()
);
});
}
Return custom search results as WirechatUserResource instances so each result includes the expected id, type, wirechat_name, wirechat_avatar_url, and wirechat_subtitle values.
Keep application-level visibility rules in this query too. The same callback is used when starting chats, creating groups, adding members, and sharing invite links, so tenant, status, role, or blocking filters should be applied before results are shown. Wirechat still enforces group-add privacy and canSendMessageTo() before the final action.
The example only returns active users and limits matching to the name field.
Accessing Conversations
Use the conversations() relationship on the authenticated user to access conversations where that user is an active participant.
- Via Wirechat UI
Navigate to the /chats route to view your active conversations. Conversations that you have deleted, groups you have exited, or conversations without any messages will not appear in the list.
- Programmatically
$auth = auth()->user();
$conversations = $auth->conversations()->get();
Conversation Scopes
The conversations() relationship includes scopes for common list filters.
Exclude blank conversations:
$conversations = $auth->conversations()->withoutBlanks()->get();
Exclude deleted conversations:
$conversations = $auth->conversations()->withoutDeleted()->get();
Scopes only take effect when the user is authenticated.
Filtering Conversations in a Panel
Use modifyConversationsQuery() in a panel provider when a panel should only list a specific kind of conversation, such as private chats:
use Illuminate\Database\Eloquent\Builder;
use Wirechat\Wirechat\Enums\ConversationType;
use Wirechat\Wirechat\Panel;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->modifyConversationsQuery(function (Builder $query) {
return $query->where('type', ConversationType::PRIVATE);
});
}
The callback receives the conversations query. It can also receive the authenticated model when the filter needs user-specific data. You may mutate the builder directly or return a builder.
Wirechat applies this hook before ordering and cursor pagination. Use it for list filtering, such as showing only private, self, or group conversations. Keep authorization rules enforced in your application middleware or policies.
Conversation Membership
Check whether a user is part of a conversation using the belongsToConversation() method:
$conversation = Wirechat\Wirechat\Models\Conversation::first();
$user->belongsToConversation($conversation); // Returns a boolean
Check if a Conversation Exists Between Users
$anotherUser = User::first();
$user->hasConversationWith($anotherUser); // Returns a boolean