In this post, How to Integrate WhatsApp Order Notifications in Magento 2 Using WaAPI
Let's start it by creating custom extension.
Find Complete module files on Magelearn_OrderPopup
Create folder inside app/code/Magelearn/OrderPopup
Add registration.php file in it:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Magelearn_OrderPopup',
__DIR__
);
Add composer.json file in it:{
"name": "magelearn/module-orderpopup",
"description": "Magento 2 WhatsApp order notification module",
"type": "magento2-module",
"license": "proprietary",
"authors": [
{
"name": "Magelearn"
}
],
"minimum-stability": "dev",
"require": {},
"autoload": {
"psr-4": {
"Magelearn\\OrderPopup\\": ""
},
"files": [
"registration.php"
]
}
}Add etc/module.xml file in it:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magelearn_OrderPopup">
<sequence>
<module name="Magento_Sales"/>
</sequence>
</module>
</config>Add etc/adminhtml/system.xml to give admin configurations.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="magelearn_orderpopup"
translate="label"
sortOrder="900"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WhatsApp Order Notification</label>
<tab>sales</tab>
<resource>Magelearn_OrderPopup::config</resource>
<group id="whatsapp"
translate="label"
sortOrder="10"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WhatsApp Settings</label>
<field id="enabled"
translate="label"
type="select"
sortOrder="10"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>Enable WhatsApp Notification</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="auto_send"
translate="label"
type="select"
sortOrder="20"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>Send Automatically After Order Placement</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<depends>
<field id="enabled">1</field>
</depends>
</field>
<field id="provider"
translate="label"
type="select"
sortOrder="30"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WhatsApp Provider</label>
<source_model>Magelearn\OrderPopup\Model\Config\Source\Provider</source_model>
</field>
<field id="country_code"
translate="label"
type="text"
sortOrder="40"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>Default Country Code</label>
<comment>Example: 91 for India. Do not include +.</comment>
</field>
<field id="message_template"
translate="label"
type="textarea"
sortOrder="50"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>Order Message Template</label>
<frontend_model>Magelearn\OrderPopup\Block\Adminhtml\System\Config\MessageTemplate</frontend_model>
</field>
</group>
<group id="waapi"
translate="label"
sortOrder="20"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WaAPI Configuration</label>
<field id="instance_id"
translate="label"
type="text"
sortOrder="10"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WaAPI Instance ID</label>
</field>
<field id="api_token"
translate="label"
type="obscure"
sortOrder="20"
showInDefault="1"
showInWebsite="1"
showInStore="1">
<label>WaAPI API Token</label>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
</field>
</group>
</section>
</system>
</config>As per highlighted code, we will add Model/Config/Source/Provider.php file.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Model\Config\Source;
use Magento\Framework\Data\OptionSourceInterface;
class Provider implements OptionSourceInterface
{
public function toOptionArray(): array
{
return [
[
'value' => 'waapi',
'label' => __('WaAPI'),
],
];
}
}And to display the Message Template Front-end Model class, we will add Block/Adminhtml/System/Config/MessageTemplate.php file.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Block\Adminhtml\System\Config;
use Magento\Config\Block\System\Config\Form\Field;
use Magento\Framework\Data\Form\Element\AbstractElement;
class MessageTemplate extends Field
{
/**
* Render the message template field.
*/
protected function _getElementHtml(
AbstractElement $element
): string {
$html = parent::_getElementHtml($element);
$variables = [
'{{customer_name}}' => 'Customer first name and last name',
'{{increment_id}}' => 'Magento order number',
'{{order_total}}' => 'Order grand total',
'{{currency}}' => 'Order currency code, e.g. USD or CAD',
'{{store_name}}' => 'Magento store name',
'{{shipping_method}}' => 'Selected shipping method',
'{{payment_method}}' => 'Selected payment method',
'{{billing_address}}' => 'Customer billing address',
'{{shipping_address}}' => 'Customer shipping address',
];
$html .= '<div class="magelearn-message-template-help">';
$html .= '<strong>Available Variables</strong>';
$html .= '<p>Use the following variables in your message template. '
. 'They will be automatically replaced with the order information '
. 'when the message is sent.</p>';
$html .= '<table class="admin__table-secondary">';
$html .= '<thead>';
$html .= '<tr>';
$html .= '<th>Variable</th>';
$html .= '<th>Description</th>';
$html .= '</tr>';
$html .= '</thead>';
$html .= '<tbody>';
foreach ($variables as $variable => $description) {
$html .= '<tr>';
$html .= '<td><code>'
. $this->escapeHtml($variable)
. '</code></td>';
$html .= '<td>'
. $this->escapeHtml($description)
. '</td>';
$html .= '</tr>';
}
$html .= '</tbody>';
$html .= '</table>';
$html .= '</div>';
return $html;
}
}Add etc/acl.xml file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Sales::sales">
<resource
id="Magelearn_OrderPopup::send_whatsapp"
title="Send WhatsApp Order Notification"
sortOrder="10"
/>
</resource>
<resource
id="Magelearn_OrderPopup::config"
title="WhatsApp Order Notification Configuration"
sortOrder="20"
/>
</resource>
</resources>
</acl>
</config>Now Create your di.xml file inside etc and use plugin method to add button HTML code on sales order view page as well as API insterface for sending Whatsapp Messages.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Sales\Block\Adminhtml\Order\View">
<plugin
name="magelearn_orderpopup_order_view"
type="Magelearn\OrderPopup\Plugin\Magento\Sales\Block\Adminhtml\Order\View"
sortOrder="10"
/>
</type>
<preference
for="Magelearn\OrderPopup\Api\WhatsAppServiceInterface"
type="Magelearn\OrderPopup\Model\WhatsApp\WaApiService"
/>
</config>First we will add Api/WhatsAppServiceInterface.php and define our sendMessage() function.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Api;
interface WhatsAppServiceInterface
{
/**
* Send WhatsApp message.
*
* @param string $phoneNumber
* @param string $message
* @return bool
*/
public function sendMessage(
string $phoneNumber,
string $message,
?int $storeId = null
): bool;
}And will add our Model class at Model/WhatsApp/WaApiService.php
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Model\WhatsApp;
use Magelearn\OrderPopup\Api\WhatsAppServiceInterface;
use Magelearn\OrderPopup\Model\Config;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\Client\Curl;
use Psr\Log\LoggerInterface;
class WaApiService implements WhatsAppServiceInterface
{
private const API_URL =
'https://waapi.app/api/v1/instances/%s/client/action/send-message';
public function __construct(
private readonly Curl $curl,
private readonly Config $config,
private readonly LoggerInterface $logger
) {
}
/**
* @inheritDoc
*/
public function sendMessage(
string $phoneNumber,
string $message,
?int $storeId = null
): bool {
$instanceId = $this->config->getWaApiInstanceId($storeId);
$apiToken = $this->config->getWaApiToken($storeId);
$this->logger->info(
'WaAPI configuration loaded.',
[
'instance_id' => $instanceId,
'token_length' => strlen($apiToken),
'token_is_encrypted' => str_starts_with($apiToken, '0:'),
]
);
if ($instanceId === '' || $apiToken === '') {
$this->logger->error(
'WaAPI configuration is incomplete.'
);
throw new LocalizedException(
__('WaAPI configuration is incomplete.')
);
}
$chatId = $this->buildChatId($phoneNumber);
$url = sprintf(self::API_URL, $instanceId);
$payload = [
'chatId' => $chatId,
'message' => $message,
];
try {
$this->logger->info('WaAPI: before setHeaders.');
$this->curl->setHeaders([
'Authorization' => 'Bearer ' . $apiToken,
'Content-Type' => 'application/json',
]);
$this->logger->info('WaAPI: headers configured.');
$this->curl->setOption(CURLOPT_TIMEOUT, 15);
$this->logger->info('WaAPI: before POST.', [
'url' => $url,
'chat_id' => $chatId,
]);
$this->curl->post(
$url,
json_encode($payload, JSON_THROW_ON_ERROR)
);
$this->logger->info('WaAPI: POST completed.');
$status = $this->curl->getStatus();
$response = $this->curl->getBody();
$this->logger->info(
'WaAPI response received.',
[
'status' => $status,
'response' => $response,
]
);
if ($status < 200 || $status >= 300) {
$this->logger->info(
'WaAPI request failed.',
[
'status' => $status,
'response' => $response,
]
);
return false;
}
$responseData = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
return ($responseData['data']['status'] ?? '') === 'success';
} catch (\Throwable $exception) {
$$this->logger->info(
'Unable to send WhatsApp message through WaAPI.',
[
'exception_class' => get_class($exception),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]
);
return false;
}
}
private function buildChatId(string $phoneNumber): string
{
$phoneNumber = preg_replace('/\D+/', '', $phoneNumber);
if ($phoneNumber === '') {
throw new LocalizedException(
__('Invalid WhatsApp phone number.')
);
}
if (str_starts_with($phoneNumber, '0')) {
$phoneNumber = ltrim($phoneNumber, '0');
}
$countryCode = preg_replace(
'/\D+/',
'',
$this->config->getCountryCode()
);
if (
$countryCode !== ''
&& !str_starts_with($phoneNumber, $countryCode)
) {
$phoneNumber = $countryCode . $phoneNumber;
}
return $phoneNumber . '@c.us';
}
}Now create plugin file View.php inside app/code/Magelearn/OrderPopup/Plugin/Magento/Sales/Block/Adminhtml/Order
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Plugin\Magento\Sales\Block\Adminhtml\Order;
use Magento\Sales\Block\Adminhtml\Order\View as OrderView;
class View
{
public function beforeSetLayout(
OrderView $subject,
$layout
): array {
$subject->addButton(
'sendorderwhatsapp',
[
'label' => __('Send WhatsApp'),
'onclick' => 'require(["jquery"], function ($) {
$("#popup-modal").modal("openModal");
});',
'class' => 'action-default',
]
);
return [$layout];
}
}Now we will add the layout file sales_order_view.xml and will modify the Sales Order View Page.
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block
class="Magelearn\OrderPopup\Block\Adminhtml\Order\ModalBox"
name="magelearn.orderpopup.modal"
template="Magelearn_OrderPopup::order/modalbox.phtml"
after="-"
/>
</referenceContainer>
</body>
</page>Now we will create a Block and template file as per the Layout.
<?php
/**
* @var \Magelearn\OrderPopup\Block\Adminhtml\Order\ModalBox $block
*/
?>
<div id="popup-modal" style="display: none;">
<div class="admin__fieldset">
<div class="admin__field field">
<label class="admin__field-label" for="whatsapp-phone">
<span><?= $block->escapeHtml(__('Phone Number')) ?></span>
</label>
<div class="admin__field-control">
<input
type="text"
id="whatsapp-phone"
name="phone"
class="admin__control-text"
value="<?= $block->escapeHtmlAttr($block->getOrderPhone()) ?>"
/>
</div>
</div>
<div class="admin__field field">
<label class="admin__field-label" for="whatsapp-message">
<span><?= $block->escapeHtml(__('Message')) ?></span>
</label>
<div class="admin__field-control">
<textarea
id="whatsapp-message"
name="message"
rows="8"
class="admin__control-textarea"
><?= $block->escapeHtml($block->getMessage()) ?></textarea>
</div>
</div>
</div>
</div>
<script>
require([
'jquery',
'Magento_Ui/js/modal/modal',
'mage/translate'
], function ($, modal) {
'use strict';
var options = {
type: 'popup',
responsive: true,
innerScroll: true,
title: $.mage.__('Send WhatsApp Message'),
modalClass: 'magelearn-whatsapp-modal',
buttons: [
{
text: $.mage.__('Send WhatsApp'),
class: 'action-primary',
click: function () {
var popup = this;
$.ajax({
url: '<?= $block->escapeUrl($block->getFormUrl()) ?>',
type: 'POST',
dataType: 'json',
data: {
form_key: window.FORM_KEY,
phone: $('#whatsapp-phone').val(),
message: $('#whatsapp-message').val()
},
showLoader: true
}).done(function (response) {
if (response.success) {
alert(response.message);
popup.closeModal();
return;
}
alert(response.message);
}).fail(function () {
alert(
$.mage.__(
'Unable to send the WhatsApp message.'
)
);
});
}
},
{
text: $.mage.__('Close'),
class: '',
click: function () {
this.closeModal();
}
}
]
};
modal(
options,
$('#popup-modal')
);
});
</script>Now, Create Block file ModalBox.php inside Block/Adminhtml/Order/
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Block\Adminhtml\Order;
use Magelearn\OrderPopup\Model\MessageTemplate;
use Magento\Backend\Block\Template;
use Magento\Backend\Block\Template\Context;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
class ModalBox extends Template
{
private ?OrderInterface $order = null;
public function __construct(
Context $context,
private readonly OrderRepositoryInterface $orderRepository,
private readonly MessageTemplate $messageTemplate,
private readonly RequestInterface $request,
array $data = []
) {
parent::__construct($context, $data);
}
public function getInfo(): string
{
return (string) __('Send WhatsApp Order Notification');
}
public function getFormUrl(): string
{
return $this->getUrl(
'orderpopup/order/order',
[
'order_id' => $this->getOrder()
? (int) $this->getOrder()->getEntityId()
: 0,
]
);
}
public function getOrder(): ?OrderInterface
{
if ($this->order !== null) {
return $this->order;
}
$orderId = (int) $this->request->getParam('order_id');
if ($orderId <= 0) {
return null;
}
try {
$this->order = $this->orderRepository->get($orderId);
} catch (NoSuchEntityException) {
return null;
}
return $this->order;
}
public function getOrderPhone(): string
{
$order = $this->getOrder();
if (!$order) {
return '';
}
$shippingAddress = $order->getShippingAddress();
if ($shippingAddress && $shippingAddress->getTelephone()) {
return (string) $shippingAddress->getTelephone();
}
$billingAddress = $order->getBillingAddress();
if ($billingAddress && $billingAddress->getTelephone()) {
return (string) $billingAddress->getTelephone();
}
return '';
}
public function getMessage(): string
{
$order = $this->getOrder();
if (!$order) {
return '';
}
return $this->messageTemplate->getMessage($order);
}
}
Now as per the highlighted code above, to display the message template in the Modal Popup when clicking on "Send Whatsapp" button we will add Model/MessageTemplate.php file.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Model;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderAddressInterface;
class MessageTemplate
{
public function __construct(
private readonly Config $config
) {
}
public function getMessage(
OrderInterface $order
): string {
$storeId = (int) $order->getStoreId();
$template = $this->config->getMessageTemplate($storeId);
$customerName = trim(
(string) $order->getCustomerFirstname()
. ' '
. (string) $order->getCustomerLastname()
);
return strtr(
$template,
[
'{{customer_name}}' => $customerName,
'{{increment_id}}' => (string) $order->getIncrementId(),
'{{order_total}}' => (string) $order->getGrandTotal(),
'{{currency}}' => (string) $order->getOrderCurrencyCode(),
'{{store_name}}' => (string) $order->getStore()->getName(),
'{{shipping_method}}' => $this->getShippingMethod($order),
'{{payment_method}}' => $this->getPaymentMethod($order),
'{{billing_address}}' => $this->getBillingAddress($order),
'{{shipping_address}}' => $this->getShippingAddress($order),
]
);
}
private function getShippingMethod(OrderInterface $order): string
{
return (string) $order->getShippingDescription();
}
private function getPaymentMethod(OrderInterface $order): string
{
$payment = $order->getPayment();
if (!$payment) {
return '';
}
return (string) $payment->getAdditionalInformation('method_title');
}
private function getBillingAddress(OrderInterface $order): string
{
$address = $order->getBillingAddress();
if (!$address) {
return '';
}
return $this->formatAddress($address);
}
private function getShippingAddress(OrderInterface $order): string
{
$address = $order->getShippingAddress();
if (!$address) {
return '';
}
return $this->formatAddress($address);
}
private function formatAddress(
OrderAddressInterface $address
): string
{
$lines = [
trim(
(string) $address->getFirstname()
. ' '
. (string) $address->getLastname()
),
...$address->getStreet(),
trim(
(string) $address->getCity()
. ', '
. (string) $address->getRegion()
. ' '
. (string) $address->getPostcode()
),
(string) $address->getCountryId(),
(string) $address->getTelephone(),
];
return implode(
PHP_EOL,
array_filter(
$lines,
static fn ($line): bool => trim((string) $line) !== ''
)
);
}
}Also here in block file getFormUrl() function, we have give a link for form action. Which call to route (controller) file.
So for that, Create routes.xml file inside etc/adminhtml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
<router id="admin">
<route id="orderpopup" frontName="orderpopup">
<module name="Magelearn_OrderPopup"/>
</route>
</router>
</config>Now Create, controller file Order.php inside Controller/Adminhtml/Order/
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Controller\Adminhtml\Order;
use Magelearn\OrderPopup\Model\WhatsApp\ServiceFactory;
use Magento\Backend\App\Action;
use Magento\Framework\App\Response\Http\FileFactory;
use Magento\Framework\Controller\Result\Json;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Controller\Result\RawFactory;
use Magento\Framework\Registry;
use Magento\Framework\Translate\InlineInterface;
use Magento\Framework\View\Result\LayoutFactory;
use Magento\Framework\View\Result\PageFactory;
use Magento\Sales\Api\OrderManagementInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Controller\Adminhtml\Order as AdminOrder;
use Psr\Log\LoggerInterface;
class Order extends AdminOrder
{
public const ADMIN_RESOURCE = 'Magelearn_OrderPopup::send_whatsapp';
public function __construct(
Action\Context $context,
Registry $coreRegistry,
FileFactory $fileFactory,
InlineInterface $translateInline,
PageFactory $resultPageFactory,
JsonFactory $resultJsonFactory,
LayoutFactory $resultLayoutFactory,
RawFactory $resultRawFactory,
OrderManagementInterface $orderManagement,
OrderRepositoryInterface $orderRepository,
LoggerInterface $logger,
private readonly ServiceFactory $serviceFactory
) {
parent::__construct(
$context,
$coreRegistry,
$fileFactory,
$translateInline,
$resultPageFactory,
$resultJsonFactory,
$resultLayoutFactory,
$resultRawFactory,
$orderManagement,
$orderRepository,
$logger
);
}
public function execute(): Json
{
$resultJson = $this->resultJsonFactory->create();
$order = $this->_initOrder();
if (!$order) {
return $resultJson->setData([
'success' => false,
'message' => __('Unable to load the order.'),
]);
}
$phone = trim(
(string) $this->getRequest()->getParam('phone')
);
$message = trim(
(string) $this->getRequest()->getParam('message')
);
if ($phone === '') {
return $resultJson->setData([
'success' => false,
'message' => __('Please enter a phone number.'),
]);
}
if ($message === '') {
return $resultJson->setData([
'success' => false,
'message' => __('Please enter a message.'),
]);
}
try {
$service = $this->serviceFactory->create(
(int) $order->getStoreId()
);
$success = $service->sendMessage(
$phone,
$message,
(int) $order->getStoreId()
);
if (!$success) {
return $resultJson->setData([
'success' => false,
'message' => __('Unable to send the WhatsApp message.'),
]);
}
return $resultJson->setData([
'success' => true,
'message' => __('WhatsApp message sent successfully.'),
]);
} catch (\Throwable $exception) {
$this->logger->error(
'Unable to send manual WhatsApp order notification.',
[
'order_id' => $order->getId(),
'exception' => $exception,
]
);
return $resultJson->setData([
'success' => false,
'message' => __('An error occurred while sending the message.'),
]);
}
}
}
Now as per the highlighted code above, we will add our Factory class at Model/WhatsApp/ServiceFactory.php
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Model\WhatsApp;
use Magelearn\OrderPopup\Api\WhatsAppServiceInterface;
use Magelearn\OrderPopup\Model\Config;
use Magento\Framework\Exception\LocalizedException;
class ServiceFactory
{
public function __construct(
private readonly Config $config,
private readonly WaApiService $waApiService
) {
}
public function create(?int $storeId = null): WhatsAppServiceInterface
{
$provider = $this->config->getProvider($storeId);
return match ($provider) {
'waapi' => $this->waApiService,
default => throw new LocalizedException(
__('Unsupported WhatsApp provider: %1', $provider)
),
};
}
}Also as per highlighted code above, we will add Model/Config.php file.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Model;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Store\Model\ScopeInterface;
class Config
{
private const XML_PATH_ENABLED = 'magelearn_orderpopup/whatsapp/enabled';
private const XML_PATH_AUTO_SEND = 'magelearn_orderpopup/whatsapp/auto_send';
private const XML_PATH_PROVIDER = 'magelearn_orderpopup/whatsapp/provider';
private const XML_PATH_WAAPI_INSTANCE_ID =
'magelearn_orderpopup/waapi/instance_id';
private const XML_PATH_WAAPI_API_TOKEN =
'magelearn_orderpopup/waapi/api_token';
private const XML_PATH_COUNTRY_CODE =
'magelearn_orderpopup/whatsapp/country_code';
private const XML_PATH_MESSAGE_TEMPLATE =
'magelearn_orderpopup/whatsapp/message_template';
public function __construct(
private readonly ScopeConfigInterface $scopeConfig,
private readonly EncryptorInterface $encryptor
) {
}
public function isEnabled(?int $storeId = null): bool
{
return $this->scopeConfig->isSetFlag(
self::XML_PATH_ENABLED,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
public function isAutoSendEnabled(?int $storeId = null): bool
{
return $this->scopeConfig->isSetFlag(
self::XML_PATH_AUTO_SEND,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
public function getProvider(?int $storeId = null): string
{
return (string) $this->scopeConfig->getValue(
self::XML_PATH_PROVIDER,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
public function getWaApiInstanceId(?int $storeId = null): string
{
return (string) $this->scopeConfig->getValue(
self::XML_PATH_WAAPI_INSTANCE_ID,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
public function getWaApiToken(?int $storeId = null): string
{
$value = (string) $this->scopeConfig->getValue(
self::XML_PATH_WAAPI_API_TOKEN,
ScopeInterface::SCOPE_STORE,
$storeId
);
if ($value === '') {
return '';
}
if (!str_starts_with($value, '0:')) {
return $value;
}
return $this->encryptor->decrypt($value);
}
public function getCountryCode(?int $storeId = null): string
{
return (string) $this->scopeConfig->getValue(
self::XML_PATH_COUNTRY_CODE,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
public function getMessageTemplate(?int $storeId = null): string
{
return (string) $this->scopeConfig->getValue(
self::XML_PATH_MESSAGE_TEMPLATE,
ScopeInterface::SCOPE_STORE,
$storeId
);
}
}Also to send the whatsapp message automatically after placing an order, we will add event observer.
For that, first add etc/events.xml file.
For that, first add etc/events.xml file.
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_order_place_after">
<observer
name="magelearn_orderpopup_send_order_whatsapp"
instance="Magelearn\OrderPopup\Observer\SendOrderWhatsApp"
/>
</event>
</config>And Observer file at Observer/SendOrderWhatsApp.php file.
<?php
declare(strict_types=1);
namespace Magelearn\OrderPopup\Observer;
use Magelearn\OrderPopup\Model\Config;
use Magelearn\OrderPopup\Model\WhatsApp\ServiceFactory;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Api\Data\OrderInterface;
use Magelearn\OrderPopup\Model\MessageTemplate;
use Psr\Log\LoggerInterface;
class SendOrderWhatsApp implements ObserverInterface
{
public function __construct(
private readonly Config $config,
private readonly ServiceFactory $serviceFactory,
private readonly MessageTemplate $messageTemplate,
private readonly LoggerInterface $logger
) {
}
/**
* @inheritDoc
*/
public function execute(Observer $observer): void
{
/** @var OrderInterface|null $order */
$order = $observer->getEvent()->getOrder();
if (!$order || !$order->getEntityId()) {
return;
}
$storeId = (int) $order->getStoreId();
if (
!$this->config->isEnabled($storeId)
|| !$this->config->isAutoSendEnabled($storeId)
) {
return;
}
$phoneNumber = $this->getOrderPhoneNumber($order);
if ($phoneNumber === '') {
$this->logger->warning(
'Unable to send WhatsApp order notification because phone number is missing.',
[
'order_id' => $order->getEntityId(),
]
);
return;
}
$message = $this->messageTemplate->getMessage($order);
try {
$service = $this->serviceFactory->create($storeId);
$service->sendMessage(
$phoneNumber,
$message,
$storeId
);
} catch (\Throwable $exception) {
$this->logger->error(
'Unable to send automatic WhatsApp order notification.',
[
'order_id' => $order->getEntityId(),
'exception' => $exception,
]
);
}
}
private function getOrderPhoneNumber(OrderInterface $order): string
{
$shippingAddress = $order->getShippingAddress();
if ($shippingAddress && $shippingAddress->getTelephone()) {
return (string) $shippingAddress->getTelephone();
}
$billingAddress = $order->getBillingAddress();
if ($billingAddress && $billingAddress->getTelephone()) {
return (string) $billingAddress->getTelephone();
}
return '';
}
}Now to display textare for Message Template and its information display properly add CSS file at view/adminhtml/web/css/source/_module.less
After adding all those files, New "Send WhatApp" button will be added on Sales order view page.
On click on that button one modal window will open with Pre-filled customer Phone number and message template form.
And after clicking on "Send WhatsApp" button one message will be send on the added customer Phone number Whatsapp.
And after clicking on "Send WhatsApp" button one message will be send on the added customer Phone number Whatsapp.

0 Comments On "Magento2 WhatsApp Order Notification Module with API Integration"