Skip to content

Developer notes

Path Purpose
app/addons/kv_order_notifications_messaging/addon.xml Settings (General, Telegram, WhatsApp, SMS, License), tables, privileges, install/uninstall functions
init.php Hook registration, synchronizer and licence blocks
func.php Hook handlers, licence gate fn_kv_order_notifications_messaging_is_licensed(), install (default rules, verify token), uninstall, cron info
controllers/backend/kv_order_notifications_messaging.php Pages log, rules, update_rule, optins, vendor; actions (rules, retry, process, test tools, opt-ins, vendor Telegram connect); console process
controllers/backend/addons.post.php Data for the settings tabs (channel status, webhook URLs)
controllers/frontend/kv_order_notifications_messaging.php worker (background queue run), whatsapp_webhook, twilio_status, unsubscribe
controllers/frontend/checkout.pre.php, checkout.post.php, profiles.post.php Opt-in checkbox data and the checkout choice
Tygh/Addons/KvOrderNotificationsMessaging/Messaging/* The messaging kit (see below)
.../Notifier.php Event → rules → recipients → queued messages
.../Rules.php Rule repository, validation, defaults, variables per event
.../Variables.php Order, shipment, product and review variables; sample values
.../Consent.php Customer opt-ins, phone of an order, signed opt-out tokens
.../Vendors.php Vendor recipients and events, Telegram connect code
.../Service.php Wires the kit: queue table, providers from the storefront’s settings, licence gate, delivery after the response, purge
.../Config.php Typed settings, per storefront in Ultimate (Config::forCompany())
.../Log.php Delivery log queries
.../StorageData.php Run marks (files while the full page cache is active)
.../License/Client.php, License/Ed25519.php Domain-bound licence client (generated)
.../Upgrade/Synchronizer.php Self-healing in-place upgrades (generated)
controllers/backend/kv_order_notifications_messaging_license.php “Check now” and cron licence check (generated)
schemas/menu/menu.post.php, menu_vendor.post.php Orders → Order messaging (admin), Orders → Message notifications (vendor, also with the Vendor panel configurator)
schemas/permissions/admin.post.php, vendor_multivendor.post.php Privileges; vendors may only use vendor and vendor_telegram
schemas/security/csrf_validation.post.php CSRF check for the storefront opt-out form
schemas/gdpr/user_data.post.php GDPR export and anonymization of opt-ins and messages
design/backend/templates/addons/kv_order_notifications_messaging/views/kv_order_notifications_messaging/*.tpl Admin and vendor pages
.../settings/{overview,telegram,whatsapp,sms}.tpl Setup help and test tools on the settings tabs
.../license/{card,status_bar,badge,info}.tpl Licence UI (generated)
design/backend/css/addons/kv_order_notifications_messaging/styles.less, js/addons/kv_order_notifications_messaging/backend.js Admin styles (scoped .kv-onm*) and tools (no external libraries)
var/themes_repository/responsive/templates/addons/kv_order_notifications_messaging/hooks/checkout/terms_and_conditions_extra.post.tpl, hooks/profiles/account_update.post.tpl, views/kv_order_notifications_messaging/unsubscribe.tpl Storefront opt-in and opt-out
Table Contents
cscart_kv_onm_messages Queue and delivery log: dedupe_key (unique), event, rule, order, company, recipient type (A/V/C), channel, provider, recipient, payload (JSON, ASCII-escaped), status (Q/P/R/S/F/X), delivery (sent/delivered/read/failed), attempts, next attempt, timestamps, provider message ID, HTTP status, error, claim
cscart_kv_onm_rules Rules: company (Ultimate storefront, 0 = all), event, status, recipient, channel, message, WhatsApp template/language/parameters, active, position
cscart_kv_onm_optins One row per phone (E.164): status Y/N, user, source, IP, timestamps
cscart_kv_onm_vendors Per vendor: Telegram chat and title, WhatsApp and SMS numbers, events

Characters outside the Basic Multilingual Plane (most emoji) are stored as numeric entities (🛒), because CS-Cart connects with the 3-byte utf8 charset; they are turned back into characters for plain-text channels and the editor, and Telegram’s HTML mode understands them.

All hooks exist with identical arguments in CS-Cart 4.17.2 and 4.21.2. Handlers only insert queue rows.

Hook Use
change_order_status_post Order placed (from status N) and status changes; skips parent orders (T)
create_shipment_post Shipment created
update_product_amount Low stock (sign -, new amount ≤ low-stock threshold, not in order management)
product_reviews_create_post New review (core product_reviews add-on)
place_order Applies the checkout opt-in choice to the order’s phone
update_profile Applies the profile opt-in choice
delete_company Removes a deleted vendor’s settings
init_templater_post Upgrade synchronizer (only while pending)

Licence: License\Client::boot() registers a static before_dispatch handler for admin/console checks and notices.

  1. A hook calls Notifier, which finds the active rules, resolves recipients (staff settings, vendor settings, customer phone + consent), renders the text and inserts one row per recipient (dedupe_key stops duplicates: one “placed” per order and recipient, one status message per change within 2 minutes, one low-stock alert per product and day).
  2. With Right away, Messaging\Dispatcher registers a shutdown function: on PHP-FPM/LiteSpeed it flushes the response and processes the queue; otherwise it starts a non-blocking GET index.php?dispatch=kv_order_notifications_messaging.worker&token=… (HMAC token of the hour, throttled to one per 2 seconds), which processes the queue.
  3. Messaging\Queue::process() claims due rows, sends them, and records the result. Transient failures (network, timeout, HTTP 5xx/429, provider rate limits) are retried after 1, 5, 15, 60 and 180 minutes or the provider’s retry_after, up to 6 attempts; rows not sent within 48 hours expire.
  4. Cron: php admin.php --dispatch=kv_order_notifications_messaging.process (prints the counts as JSON).

The kit knows nothing about orders or this add-on’s settings (configuration arrays in, Result out), so other add-ons can reuse namespaced copies of it.

Class Role
Message Channel (telegram, whatsapp, sms), recipient, text, optional WhatsApp template {name, language, params}, options (status_callback, silent)
Result ok, transient, http_status, message_id, error (never contains credentials), retry_after, data
ProviderInterface id(), channel(), isConfigured(), send(Message), test(); never throws
ProviderFactory::make($id, array $config, $api_base = '') telegram (bot_token), whatsapp_cloud (phone_number_id, access_token, api_version), twilio (account_sid, auth_token, from or messaging_service_sid), generic_http (url, method, content_type, body, headers, from, success_marker)
Providers\TelegramProvider sendMessage (HTML parse mode), getMe, recentChats() (getUpdates)
Providers\WhatsAppCloudProvider POST /{phone-number-id}/messages (template or text), phone number lookup
Providers\TwilioProvider Messages.json with basic auth and status callback, account lookup
Providers\GenericHttpProvider Any HTTP SMS API with placeholders
Http cURL client, 5 s connect / 10 s total timeout; a test transport seam
Phone E.164 normalization with a default calling code, masking, lists
Template {variable} rendering (HTML-escaped for Telegram), WhatsApp parameter lists, emoji encoding
Queue Queue + log table: enqueue(), record(), process(), retry(), applyDeliveryReports(), purge(), counters()
Dispatcher Delivery after the response, worker token
Webhook WhatsApp verify handshake and X-Hub-Signature-256, Twilio X-Twilio-Signature, status parsing

Example (inside the add-on):

use Tygh\Addons\KvOrderNotificationsMessaging\Config;
use Tygh\Addons\KvOrderNotificationsMessaging\Messaging\Message;
use Tygh\Addons\KvOrderNotificationsMessaging\Service;
$config = Config::current();
$result = Service::sendNow($config, new Message('telegram', '700100', '<b>Hello</b>'));
// or queue it: Service::enqueue($message, 'telegram', ['event' => 'custom'], $config);

Mock servers for development. Define KV_ORDER_NOTIFICATIONS_MESSAGING_API_BASE (for example http://127.0.0.1:8733) in local_conf.php of a development store: Telegram, WhatsApp and Twilio requests then go to <base>/telegram, <base>/whatsapp and <base>/twilio instead of the real APIs, and the settings show a “Development mode” notice. Never define it on a live store.

  • index.php?dispatch=kv_order_notifications_messaging.whatsapp_webhook: GET answers Meta’s hub.challenge when hub.verify_token matches; POST requires a valid X-Hub-Signature-256 (HMAC-SHA256 of the raw body with the app secret) and updates the delivery status by wamid. Status changes never go backwards (read → delivered is ignored).
  • index.php?dispatch=kv_order_notifications_messaging.twilio_status: POST with a valid X-Twilio-Signature (HMAC-SHA1 of the callback URL plus the sorted parameters with the auth token). The callback URL is only sent to Twilio from public HTTPS hosts.

The add-on prints nothing on cacheable pages. The opt-in checkbox appears only on the checkout and the profile page (never cached), and the opt-out page, the worker and the webhooks are own dispatches that the full page cache does not store. Storefront GET requests write no ?:storage_data (run marks use StorageData, files while the full page cache is active). Verified with the 4.21 full page cache: no add-on fragments in shared pages, no cache purge from storefront requests.

fn_kv_order_notifications_messaging_is_licensed() (cached per request) gates the event hooks (no rows are queued), the queue (Queue gate: nothing is sent), the checkout and profile checkbox, and the admin test sends. Admin pages, rules, the log, opt-ins, the opt-out page, webhooks and uninstall keep working. Off effect: No Telegram, WhatsApp or SMS messages are sent and the opt-in checkbox is hidden at checkout. Orders, checkout and the store e-mails keep working; rules, the delivery log and customer opt-ins are kept.