Appearance
Announcements
Current version: v0.0.5
telegram-bot-essentials/announcements (namespace TelegramBotEssentials\Announcements) lets admins compose a message once and broadcast it to every bot user, or a filtered subset. Broadcasts run with live progress, per-target delivery tracking, and can be retracted (deleted) afterwards — all without blocking the bot's normal interactive traffic.
Installation
bash
composer require telegram-bot-essentials/announcements
php artisan migratePublish config to change the queue name or batch size:
bash
php artisan vendor:publish --tag=tbe-announcements-configphp
// config/tbe-announcements.php
return [
'queue' => env('TBE_ANNOUNCEMENTS_QUEUE', 'announcements'),
'batch_size' => (int) env('TBE_ANNOUNCEMENTS_BATCH_SIZE', 100),
];Make sure a worker actually processes that queue, alongside your default one:
bash
php artisan queue:work --queue=default,announcementsDedicated queue by design
Announcements deliberately dispatch onto their own (low-priority) queue rather than default, so a broadcast to thousands of users can't starve interactive bot responses (button presses, state answers) that share the same worker pool.
Data model
| Model | Purpose |
|---|---|
Announcement | The composed message: method (html, copy, or forward), message_text/message_id/from_chat_id depending on method, sent_at, plus action_status_chat_id/action_status_message_id for the live progress message |
AnnouncementTarget | One row per recipient BotUser, with status: null (pending) → sent / forbidden (blocked/blocked-the-bot) → deleted (after retraction) |
Announcement::sendTo(int $chatId) dispatches by method:
php
'copy' => wHook()->api()->copyMessage([...]); // re-sends as a new message, no "Forwarded from" tag
'forward' => wHook()->api()->forwardMessage([...]); // keeps the "Forwarded from" tag
'html' => wHook()->api()->sendMessage([..., 'parse_mode' => 'HTML']); // freeform composed textSending flow
Admin composes & previews the announcement (sent to the admin's own chat first, to catch mistakes)
▼
"Start Sending" → targets are chunked into config('tbe-announcements.batch_size') groups
▼
SendAnnouncementJob (queued, one per chunk, exports/imports WebhookContext across the queue boundary)
│ for each target: Announcement::sendTo($peerId)
│ success → AnnouncementTarget.status = 'sent', message_id stored
│ failure (blocked/kicked/etc.) → status = 'forbidden'
▼
Progress message (action_status_chat_id/message_id) is edited live with an ASCII progress bar,
throttled via a 3-second Cache::add() lock per announcement so concurrent job completions
don't hammer editMessageText() into a 429 rate limitRetraction flow
Symmetric to sending: DeleteAnnouncementJob walks the same sent targets, calls deleteMessage() per recipient, and flips status to deleted (or forbidden if the delete call fails), updating the same throttled progress message.
Why WebhookContext matters here
Both jobs are constructed with WebhookContext $context and call wHook()->importContext($context) as the very first line of handle() — because a batch job runs on a queue worker with no incoming Telegram webhook of its own, wHook() would otherwise have no bot/API/tenant to operate with. This is the same export/import pattern documented in Reference → Webhook Context Export; Announcements is the primary real-world consumer of it in this ecosystem.
Admin UI
AnnouncementsQuery / AnnouncementsAnswer / AnnouncementsFeature / AnnouncementsKey provide the full admin flow: list, detail (with live sent/pending/deleted/forbidden counts), compose, preview, send, and retract.
Localization
Ships English (en) and Persian (fa) translations out of the box:
bash
php artisan vendor:publish --tag=tbe-announcements-translations