Skip to content

Notifly in PrestaShop

PrestaShop is extended through modules that subscribe to core hooks. Let’s build a compact notiflyalerts module that attaches to three key hooks: actionValidatedOrder (new order), actionCustomerAccountAdd (registration) and actionUpdateQuantity (product out of stock). Everything is server-side, with no JS on the frontend.

We reuse the shared notifly_send() helper — the same one as for the other CMSes. In the module it is convenient to move it into a private method, keeping the URL and token in configuration via Configuration::get().

modules/notiflyalerts/
└── notiflyalerts.php

notiflyalerts.php:

<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class NotiflyAlerts extends Module
{
public function __construct()
{
$this->name = 'notiflyalerts';
$this->tab = 'administration';
$this->version = '1.0.0';
$this->author = 'Notifly';
parent::__construct();
$this->displayName = 'Notifly Alerts';
$this->description = 'Push notifications about orders, customers and stock.';
}
public function install(): bool
{
return parent::install()
&& $this->registerHook('actionValidatedOrder')
&& $this->registerHook('actionCustomerAccountAdd')
&& $this->registerHook('actionUpdateQuantity')
&& Configuration::updateValue('NOTIFLY_URL', 'https://your-notifly.example.com')
&& Configuration::updateValue('NOTIFLY_TOKEN', 'AGdjfk_L.dKe8q');
}
public function uninstall(): bool
{
Configuration::deleteByName('NOTIFLY_URL');
Configuration::deleteByName('NOTIFLY_TOKEN');
return parent::uninstall();
}
/** Universal helper (same logic as in /cases/cms/). */
private function send(string $title, string $message, int $priority = 5): void
{
$url = Configuration::get('NOTIFLY_URL');
$token = Configuration::get('NOTIFLY_TOKEN');
if (!$url || !$token) {
return;
}
$body = json_encode([
'title' => mb_substr($title, 0, 200),
'message' => mb_substr($message, 0, 1500),
'priority' => $priority,
], JSON_UNESCAPED_UNICODE);
$ch = curl_init("$url/message?token=$token");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => $body,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
curl_close($ch);
}

actionValidatedOrder fires when the order is confirmed and payment accepted — exactly the moment worth picking up the phone for:

public function hookActionValidatedOrder(array $params): void
{
/** @var Order $order */
$order = $params['order'];
$customer = $params['customer'];
$lines = [];
foreach ($order->getProducts() as $p) {
$lines[] = "• {$p['product_name']} × {$p['product_quantity']}";
}
$this->send(
"🛒 Заказ #{$order->reference} — " .
Tools::displayPrice($order->total_paid),
"Покупатель: {$customer->firstname} {$customer->lastname}\n" .
"Оплата: {$order->payment}\n\n" .
"Состав:\n" . implode("\n", $lines) . "\n\n" .
"Админка: заказ #{$order->id}",
9 // orders — a loud priority
);
}
public function hookActionCustomerAccountAdd(array $params): void
{
/** @var Customer $customer */
$customer = $params['newCustomer'];
$this->send(
"👤 Новый клиент: {$customer->firstname} {$customer->lastname}",
"Email: {$customer->email}\n" .
"ID: {$customer->id}",
4
);
}

actionUpdateQuantity is called on any stock change. We send a push only when the product crosses the threshold, so as not to spam on every sale:

public function hookActionUpdateQuantity(array $params): void
{
$quantity = (int) $params['quantity'];
if ($quantity > 3) {
return;
}
$product = new Product((int) $params['id_product'], false, (int) $this->context->language->id);
$this->send(
"📦 Товар на исходе: {$product->name}",
"Остаток: $quantity шт.\n" .
"ID товара: {$params['id_product']}",
$quantity <= 0 ? 8 : 6
);
}
}

(the closing } ends the module class)

  1. Zip the notiflyalerts folder and upload it via Modules → Module Manager → Upload a module.
  2. After installation, set NOTIFLY_URL/NOTIFLY_TOKEN — either directly in Configuration or by adding a settings page via getContent().

The hooks are registered in the install() method, so there is no need to attach them separately.

To keep a bulk stock update (for example, from an ERP) from flooding the channel, cache the sending via Cache:

$cacheKey = 'notifly_' . md5($title);
if (Cache::getInstance()->get($cacheKey)) {
return;
}
Cache::getInstance()->set($cacheKey, 1, 60);
  • An order is visible instantly. actionValidatedOrder is already a paid order.
  • You don’t lose a product at zero stock. A zero-stock push = you restock in time.
  • Your own module instead of paid “alert” add-ons from PrestaShop Addons.
  • A module settings page with channel and threshold selection.
  • Separate Notifly channels for orders, customers and stock.
  • A deep link to the order via extras.