Налаштування веб-push сповіщень на сайті 1С-Bitrix
Веб-push сповіщення працюють через API Push браузера та Service Worker — технології, незалежні від PHP та Bitrix. Завдання Bitrix: зберігати підписки користувачів та ініціювати відправку сповіщень через події (новий замовлення, акція, нагадування про кошик). Фактична відправка йде через Web Push Protocol на сервери виробників браузерів (FCM для Chrome, Mozilla Push Service для Firefox).
Інфраструктура: VAPID-ключі та Service Worker
Для Web Push потрібні VAPID-ключі (Voluntary Application Server Identification) — пара публічного/приватного ключа для аутентифікації сервера перед сервісом push браузера. Генеруються один раз:
composer require minishlink/web-push
use Minishlink\WebPush\VAPID;
$keys = VAPID::createVapidKeys();
// ['publicKey' => '...', 'privateKey' => '...']
Публічний ключ передається браузеру при реєстрації підписки, приватний зберігається на сервері в b_option:
COption::SetOptionString('local', 'vapid_public_key', $keys['publicKey']);
COption::SetOptionString('local', 'vapid_private_key', $keys['privateKey']);
Service Worker — це JS-файл, зареєстрований браузером для фонової роботи. Він обробляє вхідні push-повідомлення, коли користувач не знаходиться на вашому сайті. Файл service-worker.js повинен розташовуватися в корені сайту (/service-worker.js), а не в піддиректорії — це обмеження браузерного scope:
self.addEventListener('push', function(event) {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon || '/local/images/push-icon.png',
data: { url: data.url }
})
);
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification.data.url));
});
Підписка користувача
На боці браузера ви запитуєте дозвіл та створюєте підписку:
async function subscribeToPush() {
const registration = await navigator.serviceWorker.register('/service-worker.js');
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_VAPID_PUBLIC_KEY')
});
// Відправити підписку на сервер
await fetch('/local/ajax/push_subscribe.php', {
method: 'POST',
body: JSON.stringify(subscription),
headers: { 'Content-Type': 'application/json' }
});
}
На сервері в /local/ajax/push_subscribe.php ви зберігаєте підписку. Створіть таблицю підписок:
CREATE TABLE b_local_push_subscription (
ID INT AUTO_INCREMENT PRIMARY KEY,
USER_ID INT, -- NULL для неавторизованих
ENDPOINT VARCHAR(500) NOT NULL,
P256DH TEXT NOT NULL,
AUTH VARCHAR(100) NOT NULL,
CREATED_AT DATETIME,
LAST_ACTIVE DATETIME,
UNIQUE KEY idx_endpoint (ENDPOINT(200))
);
Відправлення сповіщень з Bitrix
Сервісний клас для відправлення через бібліотеку minishlink/web-push:
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
function sendPushNotification(array $subscription, string $title, string $body, string $url): void {
$auth = [
'VAPID' => [
'subject' => 'https://example.com',
'publicKey' => COption::GetOptionString('local', 'vapid_public_key'),
'privateKey' => COption::GetOptionString('local', 'vapid_private_key'),
],
];
$webPush = new WebPush($auth);
$webPush->queueNotification(
Subscription::create([
'endpoint' => $subscription['ENDPOINT'],
'keys' => ['p256dh' => $subscription['P256DH'], 'auth' => $subscription['AUTH']],
]),
json_encode(['title' => $title, 'body' => $body, 'url' => $url])
);
foreach ($webPush->flush() as $report) {
if ($report->isSubscriptionExpired()) {
// Видалити застарілу підписку з b_local_push_subscription
deleteExpiredSubscription($report->getEndpoint());
}
}
}
Інтеграція з подіями Bitrix
Нагадування про кинуту кошик. Агент щогодини знаходить кошики з товарами старіше 2 годин у користувачів з підпискою та відправляє push. Таблиця b_sale_basket, фільтр за DATE_UPDATE < NOW() - INTERVAL 2 HOUR та ORDER_ID IS NULL.
Сповіщення про зміну статусу замовлення. Обробник OnSaleOrderStatusUpdate:
AddEventHandler("sale", "OnSaleOrderStatusUpdate", function($orderId, $arFields) {
if ($arFields['STATUS_ID'] === 'D') { // Delivered
$userId = CSaleOrder::GetByID($orderId)['USER_ID'];
sendPushToUser($userId, 'Замовлення доставлено', 'Ваше замовлення #' . $orderId . ' чекає вас');
}
});
Масові розсилки. Виберіть всіх підписчиків з b_local_push_subscription, відправте партіями по 100 через webPush->queueNotification() + flush(). Великі розсилки — через агент із поділом на сторінки, щоб не перевищити ліміт часу виконання скрипту.
Видаляйте застарілі підписки (endpoint повернув 404 або 410) одразу — вони накопичуються швидко та сповільнюють розсилки.







