PHPackages                             justinholtweb/pigeon - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. justinholtweb/pigeon

Active

justinholtweb/pigeon
====================

00PHP

Pushed todayCompare

[ Source](https://github.com/justinholtweb/craft-pigeon)[ Packagist](https://packagist.org/packages/justinholtweb/pigeon)[ RSS](/packages/justinholtweb-pigeon/feed)WikiDiscussions main Synced today

READMEChangelog (1)DependenciesVersionsUsed By (0)

Pigeon
======

[](#pigeon)

Two-way threaded messaging for Craft CMS 5. Pigeon gives your site a conversation inbox: customers ask a question, your team is notified and replies, and the customer is notified back — with the whole thread saved for both sides. It also supports private user-to-user direct messages between logged-in Craft users.

- **Guest ↔ admin support threads** — visitors message you without an account and return via a private, expiring link emailed to them.
- **User ↔ user direct messages** — logged-in users start conversations with each other.
- **Three notification channels** — queued email, a control-panel dashboard widget + nav badge, and on-site unread counts.
- **Built on a `Thread` element** — filterable CP inbox, search, statuses, and Trash for free.
- **Attachments, internal notes, assignment, statuses, read receipts.**

Requirements
------------

[](#requirements)

- Craft CMS 5.4.0 or later
- PHP 8.2 or later

Installation
------------

[](#installation)

From your project directory:

```
composer require justinholtweb/pigeon
php craft plugin/install pigeon
```

Then visit **Settings → Plugins → Pigeon** to configure it.

Concepts
--------

[](#concepts)

- **Thread** — a conversation. Either `support` (guest/customer ↔ staff) or `direct` (user ↔ user). Has a status: `open`, `pending` (awaiting staff), or `closed`.
- **Participant** — a party on a thread. A Craft user (by `userId`) or a guest (by `email` + a hashed access token). Each participant tracks its own read state.
- **Message** — an entry in a thread. May be a normal message, an **internal note** (visible to staff only), or a system event.

Notifications
-------------

[](#notifications)

Every new message fans out from one place. Other participants who opted in receive a queued email — staff get a control-panel link, users get a front-end link, and guests get a freshly minted token link. Run the queue to deliver:

```
php craft queue/run
```

Staff also see a **Pigeon Inbox** dashboard widget and a nav badge counting threads that need a reply.

Front-end
---------

[](#front-end)

Pigeon exposes `craft.pigeon` for logged-in users:

```
{{ craft.pigeon.unreadCount() }}            {# unread thread count #}
{% for thread in craft.pigeon.threads() %}
    {{ thread.title }}
{% endfor %}
{{ craft.pigeon.isUnread(threadId) }}
```

Built-in routes (self-contained example templates — copy and restyle as you like):

RouteWhoPurpose`pigeon/threads`logged-in userList your threads + start one`pigeon/threads/`logged-in userView &amp; reply`pigeon/t/`guestView &amp; reply via emailed link### Public "contact support" form

[](#public-contact-support-form)

Drop this anywhere (or copy `templates/_front/contact-form.twig`):

```

    {{ csrfInput() }}
    {{ actionInput('pigeon/guest/start') }}

    Send

```

The guest is emailed a private link to follow the conversation; your support recipients are alerted to the new thread.

Action endpoints
----------------

[](#action-endpoints)

ActionLoginPurpose`pigeon/guest/start`anonymousGuest starts a support thread`pigeon/guest/reply`anonymous (token)Guest replies`pigeon/guest/request-link`anonymousRe-email an expired link`pigeon/threads/start`userStart a support or direct thread`pigeon/messages/reply`userReply to a thread you're in`pigeon/admin/reply` · `/status` · `/assign`staffControl-panel actionsPermissions
-----------

[](#permissions)

- **Access Pigeon** (`pigeon:accessPlugin`) — read the inbox.
- **Manage threads** (`pigeon:manageThreads`) — reply, add notes, change status.
    - **Assign threads** (`pigeon:assignThreads`).
- **Manage settings** (`pigeon:manageSettings`).

Anti-spam
---------

[](#anti-spam)

Guest forms are protected by a per-IP fixed-window rate limit and an optional honeypot field, both configurable in settings.

License
-------

[](#license)

See [LICENSE.md](LICENSE.md).

###  Health Score

20

—

LowBetter than 13% of packages

Maintenance65

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity8

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/035cb655c55af0e9e5b96754b80fd9703e195c32dbdfc49ae9a43ab9cf8db560?d=identicon)[justinholtweb](/maintainers/justinholtweb)

---

Top Contributors

[![justinholtweb](https://avatars.githubusercontent.com/u/295903?v=4)](https://github.com/justinholtweb "justinholtweb (3 commits)")

### Embed Badge

![Health badge](/badges/justinholtweb-pigeon/health.svg)

```
[![Health](https://phpackages.com/badges/justinholtweb-pigeon/health.svg)](https://phpackages.com/packages/justinholtweb-pigeon)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
