Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wirechat Laravel Package

namu/wirechat

WireChat is a Laravel Livewire package for adding real-time private and group chat to your app. It offers media attachments, emoji reactions, read receipts, typing indicators, moderation tools, and a customizable Tailwind UI, with easy setup and integration.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and publish

composer require namu/wirechat
php artisan vendor:publish --tag=wirechat-config
php artisan vendor:publish --tag=wirechat-migrations
php artisan migrate
php artisan storage:link   # required for attachments/avatars to resolve

v0.6.0 drops Laravel 10 — you need Laravel 11+ (tested against 12/13 and PHP 8.5). If you are upgrading, run composer why-not namu/wirechat before anything else; that is the usual first blocker.

The migration set grew in this release (message requests, per-user settings, encryption message metadata). Publish and run migrations before touching config, then re-read config/wirechat.php — several new keys are inert until you republish.

Wirechat is panel-driven, so nothing is routable until you register a panel. Mirror workbench/app/Providers/Wirechat/TestPanelProvider.php and register it in bootstrap/providers.php:

class AppPanelProvider extends PanelProvider
{
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->id('app')
            ->path('chat')
            ->default()
            ->guards(['web'])
            ->middleware(['web', 'auth'])
            ->chatMiddleware(['auth'])
            ->messageRequests(true)   // v0.6: approval-first 1:1 conversations
            ->settings(true);         // v0.6: per-user notification/privacy screens
    }
}

2. Wire up your user model

The package still does not assume App\Models\User. v0.6 hardened participant/sendable/auth resolution so custom user models are safer to plug in, but the contract is unchanged:

class User extends Authenticatable implements WirechatUser
{
    use InteractsWithWirechat;

    public function wirechat_name(): string { return $this->name; }
    public function wirechat_avatar_url(): ?string { return $this->avatar_url; }
    public function canAccessWirechatPanel(Panel $panel): bool { return true; }
}

InteractsWithWirechat gives you the conversation/message relations plus the new per-user settings storage. Chatable still exists for BC but is legacy — start with the trait.

3. Where to look first

  • config/wirechat.php — model overrides, table prefix, storage disk/visibility, UUID mode, encryption, message requests, settings.
  • src/Panel.php and src/Panel/Concerns/* — the real configuration surface. v0.6 added color tone, route registration toggle, mount URLs, conversations query customization, message actions, group invitations, settings, and user search behavior here.
  • workbench/app/Providers/Wirechat/* — the canonical working examples; they were regenerated with new defaults in this release, so re-read them even if you copied them months ago.
  • src/Models/Conversation.php, src/Models/Participant.php — polymorphic participant schema (participantable_id/participantable_type), now with request-state columns.

4. First use case to validate

Ship a 1:1 private chat before touching groups — but decide up front whether messageRequests is on. With requests enabled, a new 1:1 opens into a pending/approval state with its own drawer and realtime updates, not an immediately usable thread. That is a different first-run experience and a different test.

The sequence that exercises the most surface with the least code: open a 1:1 → send a message with an attachment → accept/decline a request → create a group → invite a member → send a group invite link → approve the resulting join request. Everything else (lobby screens, banned/past members, settings) is a variation on the same machinery.

Implementation Patterns

One panel per surface, not one panel per app. An app panel at /chat for customers and an admin panel at /admin/chat with different guards, layout, color tone, and upload limits. Panels resolve by id or provider class; ->default() decides which one bare wirechat component calls hit. Keep panel config in dedicated provider classes, not inline in AppServiceProvider.

Configure behavior through panel callbacks, not overrides. The seam list grew in v0.6: createChatAction(), createGroupAction(), deleteMessageActions(), clearChatAction(), searchUsersUsing(), redirectToHomeAction(), homeUrl(), plus new controls for conversation queries, mount URLs, route registration, group invitations, settings, and color tone. Before writing a custom Livewire component, check whether a panel callback already covers it — you'll avoid fighting the package on upgrades.

Message requests are a state machine, not a flag. Once enabled, private conversations have a pending/approved lifecycle with pending-message handling, request drawers, and realtime updates. Model it explicitly in your own code: don't assume a Conversation row means "visible to both parties", and don't build notification logic that fires on message creation instead of on request approval. If your app already ships 1:1 chat, enabling this flag silently changes the behavior of every new conversation — treat it as a product decision with a migration story for in-flight threads.

Groups have a full lifecycle now. Invite links → join requests → lobby/request-management → approval → active membership, plus past-member and banned-member paths. Treat permissions as data, not UI: use groupInvitations(false) and panel-level maxGroupMembers() as the first line of defense, then enforce the same rules in your own actions. invitePageLayout() remains the hook for branded onboarding, and the lobby screen is where most of the v0.6 group bug fixes landed — re-verify invite redirects, copy actions, and approval flows after the bump.

Encryption is a storage policy decision, made once. v0.6 adds configurable message encryption with metadata storage and encryption payload handling. Turn it on before you have messages you care about, decide where the key lives (env/KMS, never the DB), and accept the consequences: encrypted bodies are not server-side searchable, not reportable, and not backfillable from plaintext without a migration. Queued jobs and broadcast payloads must never carry the plaintext key or raw body.

Settings are per-user persisted state. Notification, security, and privacy settings now have storage and screens behind panel flags. That means a new table, new UI routes, and new expectations from users — wire the notification settings into your notification channels or the toggles become decorative. Disable the screens via the panel flag if you don't intend to honor them.

Multi-model participation. Participants are polymorphic, so User and Team (or Tenant) can both join conversations. Point the panel at multiple guards via guards(['web', 'admin']) and gate each model type through canAccessWirechatPanel(). Persist the participant type, never a hard-coded user FK.

Search customization is per-panel and hot-path. searchUsersUsing() receives the search context and should return a constrained, index-friendly query. Set searchableAttributes() deliberately. Group invite-link sending, join requests, and message requests all reuse the user search — a bad callback degrades several flows at once, and v0.6 explicitly touched user search behavior.

Widget mode is a separate integration. The wirechat component is the embeddable shell; mount it in a layout with package views and your compiled CSS. v0.6 changed empty states and reduced chat-list refreshes to keep widgets responsive — validate drawer/modal/Alpine behavior in both full-page and widget mode, because fixes do not transfer between them.

Overrides over forks. Register custom models via config/wirechat.php (models.conversation, models.message, models.group, …) and extend the base class. Always resolve models through the Wirechat facade/service rather than new Conversation so overrides take effect. This matters more now that conversation/message rows carry encryption and request metadata.

Attachments: render, don't reconstruct. Attachment metadata handling and secure download helpers are new. Use the package helpers for private-disk files instead of hand-rolling Storage::url(), and let the richer media rendering do its job.

Real-time and notifications. Broadcasting is panel-scoped, so Echo channel names include the panel namespace — your routes/channels.php authorization must match the panel's guard, including for the new request-update events. Use messagesQueue()/eventsQueue() to keep broadcast dispatch off the request path, and reach for webPushNotifications() (with serviceWorkerPath()) only if you actually have a service worker.

Testing. Wirechat tests with Pest + Orchestra Testbench; mirror that with a small smoke suite: Livewire::test('wirechat.chats') renders, a message can be sent, an unauthorized panel access returns 403. Add two more for 0.6: a message request can be approved, and an invite link produces a join request. Those five catch most upgrade regressions.

Gotchas and Tips

Three independent access layers — debug them in order. Route middleware (wirechat.panelAccess, belongsToConversation, wirechat.setPanel) can pass while canAccessWirechatPanel() still denies, and guards() can deny before either runs. A silent 403 is usually guard mismatch; route-not-found is usually a missing/duplicate panel id() or path() — or, new in 0.6, routes you disabled via the route-registration control. Log the resolved panel from PanelRegistry when in doubt.

Panel methods are public API, and 0.6 is a big surface expansion. ->id(), ->path(), ->guards(), and the new tone/route/mount/settings controls are treated as durable, but the surface is wide and cadence is active. Pin a minor version ("namu/wirechat": "~0.6.0") and read the changelog before bumping — a panel-config semantic change is a silent behavior change in your app.

Laravel 10 is gone. Any app still on L10 cannot take this release. Plan the framework upgrade or stay on 0.5.x deliberately; do not let composer update decide for you mid-sprint.

Message requests can silently change existing behavior. If you enable the flag on a live app, every new 1:1 becomes pending. Decide what happens to conversations created before the flag, and make sure your "unread" and notification logic understands pending-vs-approved. "Private messaging unavailable" states were a bug-fix area in this release — verify the recipient's privacy settings against your own gating logic.

uses_uuid_for_conversations and table_prefix are one-way doors. Both alter schema and route binding. Decide before your first migration; flipping them later means data migration plus broken URLs/bookmarks.

Long index names can bite you. v0.6 fixed over-long message-request migration index names, but a custom table_prefix lengthens every generated identifier and can push you back over MySQL's 64-character limit. If php artisan migrate fails on index creation, shorten the prefix before editing the vendor migration.

Attachments need storage.visibility to match your delivery strategy. Private visibility → temporary URLs and the secure download helpers; public → storage:link. Mismatched disk + visibility is the #1 cause of "uploads work but images are broken." Confirm mediaMimes()/fileMimes() and max-size options match real uploads, or the UI fails silently on oversized files.

Encryption is a migration and an operational commitment. Losing the key loses the messages. Rotating it needs a re-encrypt path for stored payloads and metadata. Backfill before enabling on an existing dataset, and audit every place you read message.body directly — including exports, admin panels, and search.

Tailwind will not find the package views automatically. Add the published Wirechat view path to your content globs (or use the package's published CSS), or you get an unstyled widget that looks like a broken install. v0.6 restyled bubbles, typography, sticky dates, and navigation backgrounds — re-check your overrides visually.

Republish after upgrades. vendor:publish --tag=wirechat-views and a config republish are needed when the package adds keys or translations; stale published config is the top cause of "new option has no effect." This release added a lot of both.

Prefer InteractsWithWirechat and accessors over patching components. wirechat_name, wirechat_avatar_url, display_name, cover_url, canCreateChats(), canCreateGroups() are designed as override points. Customizing here survives upgrades; subclassing src/Livewire/* does not.

Component aliases are integration surface. wirechat.chats, wirechat.chat, wirechat.chat.drawer, wirechat.chat.info, wirechat.chat.group.*, wirechat.modal — passing arguments in your own Blade/@livewire calls is supported, but renaming or re-registering them will collide. New request/lobby components follow the same convention; don't shadow their names.

Maturity check. MIT, actively released, but a thin downstream footprint (few/no public dependents) and pro-tier siblings — budget for reading source rather than relying on third-party answers. 0.6.0 is a large feature drop with schema changes; keep the source in vendor/ bookmarked, and wrap your integration in your own thin service/adapter so an upstream pivot or abandonment doesn't strand your domain code.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings