Corepine logo Corepine Wirechat beta
Login
Wirechat v0.6x latest

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.


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