Создаем бесплатный callback-виджет с SMS и Telegram-оповещением

В этой статье мы пошагово создадим виджет обратного звонка с красивой минималистичной анимацией и отправкой уведомлений на почту, на свой номер телефона и в мессенджер Telegram через бота. Виджет подойдет абсолютно для любого сайта на HTML или на любой CMS.

Демонстрацию можно посмотреть по ссылке.

Зачем нужен callback-виджет?

Есть масса сервисов, которые предоставляют различные настраиваемые виджеты обратного звонка — с возможностью подключить АТС, интегрировать с CRM (amoCRM, Битрикс24), с оповещением в Telegram, по СМС и так далее. За такой богатый функционал нужно платить ежемесячно, покупать минуты или выбирать тариф по карману. Стоимость подобных виджетов стартует примерно от 200 рублей в месяц.

Используя виджет, о котором мы поговорим в этой статье, вы получите навечно бесплатное, независимое и настраиваемое под любые нужды решение — с возможностью отправки заявки на почту, в Telegram и по СМС. Также с помощью вебхуков можно подключить отправку данных в CRM (если есть такая возможность на стороне самой CRM).

Минус такого виджета – отсутствие возможности онлайн-звонка. Но, думаю, это не большой минус, а скорее плюс, так как часто менеджеры не успевают ответить на звонок, и компания получает негатив от потенциального клиента. А в случае с виджетом мы принимаем заявку, выводим сообщение о том, что перезвоним в течение определенного времени, и у клиента не возникает негатива. Поэтому минус виджета может быть и плюсом.

Итак, приступим к созданию виджета.

Разметка HTML + CSS

<div class="widget-callback">

<div class="callback-button">

                               <span class="callback-button-title">Вам перезвонить?</span>

                               <span class="callback-button-phone"></span>

                </div>

                <div class="callback-form">

                               <form id="calbback-widget-form">

                                               <span class="callback-form-title">Оставьте свой телефон и мы свяжемся с вами</span>

                                               <input type="tel" name="wgphone" placeholder="+7 (999) 999 99 99" required >

                                               <input type="hidden" name="wgdata" value="Обратный звонок">

                                               <input type="hidden" name="wgpage" value="<?php echo "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; ?>">

                                               <input type="submit">

                               </form>

                </div>

</div>

Так как виджет «сквозной» и устанавливается на все страницы, нам необходимо понимать, с какой страницы был заказан обратный звонок, чтобы оперативно помочь клиенту. Для этого нам понадобится скрытое поле в форме, которое будет передавать эту страницу, значение поле должно быть таким:

<?php echo "https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; ?>

Если у вас одностраничный сайт или несколько страниц на HTML, измените расширение файла с .html на .php. Если устанавливаете на CMS , то все в порядке.

Второе скрытое поле будет передавать тему заявки — в данном случае это «Обратный звонок».

Теперь добавим небольшой скрипт открытия формы по клику на кнопку. Для этого нам понадобится подключить библиотеку jQuery и написать небольшой скрипт отправки. Если у вас уже подключена библиотека, то этого делать не стоит.

<script>

$(document).ready(function () {

                //Открытие виджета по клику

 jQuery('body').on('click', '.callback-button-phone', function (e) {

                               e.preventDefault();

                               jQuery('.widget-callback').toggleClass('widget-callback-form-open');

                });

});

</script>

Далее оформим все с помощью CSS. Вы можете добавить этот код в свой файл стилей или создать новый.

body {

                margin: 0;

                padding: 0;

}

.widget-callback {

                font-family: sans-serif;

                font-size: 14px;

}

.widget-callback>div {

                -webkit-tap-highlight-color: rgba(0, 0, 0, 0);

}

.widget-callback input {

                outline: none !important

}

.widget-callback .callback-button {

                position: absolute;

right: 60px;

bottom: 30px;

}

.widget-callback .callback-button-title {

                position: absolute;

                left: -150px;

                top: 16px;

                background: rgba(41, 41, 41, 0.75);

                color: #fff;

padding: 6px 10px;

                border-radius: 3px;

}

.widget-callback.widget-callback-form-open .callback-button-title {

                display: none;

}

.widget-callback .callback-button-title:before {

                content: '';

                position: absolute;

                width: 0;

                height: 0;

                border: solid transparent;

                border-width: 6px;

                top: 50%;

                right: -12px;

                transform: translateY(-50%);

                border-left-color: rgba(41, 41, 41, 0.75);

}

.widget-callback .callback-button-phone {

                width: 60px;

                height: 60px;

                display: block;

                background: #199c68;

                border-radius: 50%;

                position: relative;

                cursor: pointer;

                animation: 1200ms ease 0s normal none 1 running shake;

                animation-iteration-count: infinite;

                -webkit-animation: 1200ms ease 0s normal none 1 running shake;

                -webkit-animation-iteration-count: infinite;

}

.widget-callback.widget-callback-form-open .callback-button-phone {

                animation: unset;

                -webkit-animation: unset;

                background: #ddd;

}

.widget-callback .callback-button-phone:before {

                content: '';

                background: url(call.svg);

                background-size: contain;

                position: absolute;

                display: block;

                width: 24px;

                height: 24px;

                left: 50%;

                top: 50%;

                margin: -12px 0 0 -12px;

                transform: scale(1);

                -webkit-transition: all 0.2s linear;

               transition: all 0.2s linear;

}

.widget-callback .callback-button-phone:after {

                content: '';

                background: url(cancel.svg);

                background-size: contain;

                position: absolute;

                display: block;

                width: 24px;

                height: 24px;

                left: 50%;

                top: 50%;

                margin: -12px 0 0 -12px;

                transform: scale(0);

                -webkit-transition: all 0.2s linear;

               transition: all 0.2s linear;

}

.widget-callback.widget-callback-form-open .callback-button-phone:before {

                content: '';

                transform: scale(0);

}

.widget-callback.widget-callback-form-open .callback-button-phone:after {

                content: '';

                transform: scale(1);

}

.widget-callback .callback-form {

                display: none;

                background: #fff;

                border: 1px solid #f9f9f9;

                width: 240px;

                border-radius: 5px;

                padding: 30px 15px;

                right: 60px;

                bottom: 110px;

                position: absolute;

                box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.08);

}

.widget-callback.widget-callback-form-open .callback-form {

                display: block;

                animation: formcbwg-in 0.1s ease;

}

@keyframes formcbwg-in {

                0% { transform: translateY(15%); }

                100% { transform: translateY(0%); }

}

@keyframes formcbwg-out {

                0% { transform: translateY(0%); }

                100% { transform: translateY(15%); }

}

.widget-callback .callback-form-title {

                text-align: center;

                display: block;

                margin: 0 0 30px;

}

.widget-callback input {

                width: 100%;

                box-sizing: border-box;

                padding: 15px;

                margin: 0 0 10px;

                border: 1px solid #ebebeb;

                border-radius: 3px;

                font-size: 16px;

}

.widget-callback input[type="submit"] {

                background: #199c68;

                color: #fff;

                text-transform: uppercase;

                font-size: 14px;

                border: none;

                cursor: pointer;

}

.widget-callback .success-send {

                text-align: center;

}

.widget-callback .success-send img {

                width: 60px;

               margin: 0 0 20px;

}

@media (max-width: 600px) {

.widget-callback .callback-button {

right: 30px;

                bottom: 30px;

}

.widget-callback .callback-form {

width: 80%;

right: 10%;

box-sizing: border-box;

}

}

                              

                               @keyframes shake {

                               0% {

                                   transform: rotateZ(0deg);

                                       -ms-transform: rotateZ(0deg);

                                       -webkit-transform: rotateZ(0deg);

                               }

                               10% {

                                   transform: rotateZ(-30deg);

                                       -ms-transform: rotateZ(-30deg);

                                       -webkit-transform: rotateZ(-30deg);

                               }

                               20% {

                                   transform: rotateZ(15deg);

                                       -ms-transform: rotateZ(15deg);

                                       -webkit-transform: rotateZ(15deg);

                               }

                               30% {

                                   transform: rotateZ(-10deg);

                                       -ms-transform: rotateZ(-10deg);

                                       -webkit-transform: rotateZ(-10deg);

                               }

                               40% {

                                   transform: rotateZ(7.5deg);

                                       -ms-transform: rotateZ(7.5deg);

                                       -webkit-transform: rotateZ(7.5deg);

                               }

                               50% {

                                   transform: rotateZ(-6deg);

                                       -ms-transform: rotateZ(-6deg);

                                       -webkit-transform: rotateZ(-6deg);

                               }

                               60% {

                                   transform: rotateZ(5deg);

                                       -ms-transform: rotateZ(5deg);

                                       -webkit-transform: rotateZ(5deg);

                               }

                               70% {

                                   transform: rotateZ(-4.28571deg);

                                       -ms-transform: rotateZ(-4.28571deg);

                                       -webkit-transform: rotateZ(-4.28571deg);

                               }

                               80% {

                                   transform: rotateZ(3.75deg);

                                       -ms-transform: rotateZ(3.75deg);

                                       -webkit-transform: rotateZ(3.75deg);

                               }

                               90% {

                                   transform: rotateZ(-3.33333deg);

                                       -ms-transform: rotateZ(-3.33333deg);

                                       -webkit-transform: rotateZ(-3.33333deg);

                               }

                               100% {

                                   transform: rotateZ(0deg);

                                       -ms-transform: rotateZ(0deg);

                                       -webkit-transform: rotateZ(0deg);

                               }

                               }


                               @-webkit-keyframes shake {

                               0% {

                                   transform: rotateZ(0deg);

                                       -ms-transform: rotateZ(0deg);

                                       -webkit-transform: rotateZ(0deg);

                               }

                               10% {

                                   transform: rotateZ(-30deg);

                                       -ms-transform: rotateZ(-30deg);

                                       -webkit-transform: rotateZ(-30deg);

                               }

                               20% {

                                   transform: rotateZ(15deg);

                                       -ms-transform: rotateZ(15deg);

                                       -webkit-transform: rotateZ(15deg);

                               }

                               30% {

                                   transform: rotateZ(-10deg);

                                       -ms-transform: rotateZ(-10deg);

                                       -webkit-transform: rotateZ(-10deg);

                               }

                               40% {

                                   transform: rotateZ(7.5deg);

                                       -ms-transform: rotateZ(7.5deg);

                                       -webkit-transform: rotateZ(7.5deg);

                               }

                               50% {

                                   transform: rotateZ(-6deg);

                                       -ms-transform: rotateZ(-6deg);

                                       -webkit-transform: rotateZ(-6deg);

                               }

                               60% {

                                   transform: rotateZ(5deg);

                                       -ms-transform: rotateZ(5deg);

                                       -webkit-transform: rotateZ(5deg);

                               }

                               70% {

                                   transform: rotateZ(-4.28571deg);

                                       -ms-transform: rotateZ(-4.28571deg);

                                       -webkit-transform: rotateZ(-4.28571deg);

                               }

                               80% {

                                   transform: rotateZ(3.75deg);

                                       -ms-transform: rotateZ(3.75deg);

                                       -webkit-transform: rotateZ(3.75deg);

                               }

                               90% {

                                   transform: rotateZ(-3.33333deg);

                                       -ms-transform: rotateZ(-3.33333deg);

                                       -webkit-transform: rotateZ(-3.33333deg);

                               }

                               100% {

                                   transform: rotateZ(0deg);

                                       -ms-transform: rotateZ(0deg);

                                       -webkit-transform: rotateZ(0deg);

                               }

                               }

Информирование по email

Разметка готова, теперь нужно настроить отправку уведомлений на почту, для этого подключим файл mail.php со следующим содержимым:

<?php

if ($_SERVER["REQUEST_METHOD"] == "POST") {

    if (isset($_POST['wgphone'])) {$wgphone = $_POST['wgphone'];}

    if (isset($_POST['wgdata'])) {$wgdata = $_POST['wgdata'];}

    if (isset($_POST['wgpage'])) {$wgpage = $_POST['wgpage'];}


    $to = "up-lite@ya.ru"; /*Укажите адрес, на который должно приходить письмо*/

    $headers = 'MIME-Version: 1.0' . "rn";

    $headers .= "Content-type: text/html; charset=utf-8 rn";


    // дополнительные данные

    $headers .= "From: Студия Аплайт <info@up-lite.ru>;rn"; // от кого

    $subject = "$wgdata";

    $message = "

        <div style='background: #f8f8f8;padding: 20px; font-family:sans-serif;'>

            <div style='width: 400px;margin: 0 auto;'>

                <div style='    background: #1b3c56;border-radius: 10px 10px 0 0;padding: 30px 0;text-align: center;color: #fff;font-weight: 700;font-size: 20px;'>Заявка на обратный звонок

                </div>

                <div style='padding: 30px;border-radius: 0 0 10px 10px;background: #fff;'>

                    <b>Телефон:</b> <a href='tel:".$wgphone."'>".$wgphone." </a><br>

                    <b>Страница:</b> ".$wgdata."

                </div>

            </div>

        </div>

                               ";

    $send = mail ($to, $subject, $message, $headers);


    if ($send == 'true')

        {

        echo '

        <div class="success-send">

            <img src="tick.svg"> <br> Мы получили Вашу заявку и скоро с Вами свяжемся!

        </div>';

        }

        else

        {

        echo 'Нам не удалось отправить заявку, попробуйте еще раз';

        }

    } else {

        http_response_code(403);

        echo "Попробуйте еще раз";

    }

?>

Вам остается только заменить email на свой, и форма будет работать. Как видите, в теле письма мы сформировали HTML-разметку, поэтому письма будут приходить в красиво оформленном формате:

Это удобно для администратора — сразу настроенная ссылка на телефон дает возможность не копировать номер, а сразу при клике перейти в телефонную книгу.

AJAX-отправка данных формы

Теперь добавить AJAX-отправку данных формы. Это позволит отправлять номер телефона без перезагрузки, что очень удобно для посетителя.

Скрипт отправки формы:

<script>

$(document).ready(function () {

                //ajax-отправка данных

jQuery("#calbback-widget-form").submit(function () {

                        var formID = jQuery(this).attr('id');

                        var formNm = jQuery('#' + formID);

                        jQuery.ajax({

                        type: "POST",

                         url: 'mail.php',

                         data: formNm.serialize(),

                         success: function (data) { 

                                jQuery(formNm).html(data);

                          },

                          error: function (jqXHR, text, error) {

                                jQuery(formNm).html(error);        

                            }

                        });

                        return false;

                    });

});

</script>

Скрипты можно объединить в один и подключить файлом – как удобно на вашем проекте.

Отправка СМС

Для отправки сообщений на свой номер или на номер клиента будем использовать сервис sms.ru. Регистрируемся и обращаем внимание на следующее:

1. API-ключ — на каждой странице он расположен в самом низу, копируем его.

2. Файл подключения к API sms.ru — переходим по ссылке (найти ее можно в разделе «Интеграции» -> «PHP» в первой табличке).

Файл sms.ru.php небходимо поместить в корневую папку с mail.php, а затем настроить подключение и отправку в самом файле mail.php. Выглядит это следующим образом:

//ОТПРАВКА СМС

require_once 'sms.ru.php';

$smsru = new SMSRU('Ваш api_id'); // Ваш уникальный программный ключ, который можно получить на главной странице

$data = new stdClass();

$data->to = 'Ваш номер или номер админа ;

$data->text = ''.$wgdata.' '.$wgphone.''; // Текст сообщения

$sms = $smsru->send_one($data); // Отправка сообщения и возврат данных в переменную

Преимущество этого сервиса в том, что можно отправлять до 5 СМС в день на свой номер бесплатно.

Проверяем отправку данных формы и видим, что теперь приходит и оповещение на номер телефона. Данные, которые приходят в сообщении, можно менять, но чем больше текста, тем дороже СМС.

Отправка данных в чат Telegram

Для отправки данных в мессенджер нам понадобится следующее:

  1. Создать бота.
  2. Создать чат, в который бот будет отправлять данные.
  3. Активировать бота.
  4. Проверить правильность настройки.

Создаем телеграм-бота.

В строке поиска ищем BotFather и даем ему команду /start, затем выбираем команду /newbot, следуем подсказкам и выбираем имя бота и как его будем вызывать. Выбранное имя может быть занято, вам сообщит об этом подсказка, поэтому придумайте уникальное имя — чтоб наверняка 🙂

После отправки имени BotFather отправит нам сообщение о том, что все готово, и пришлет специальный ключ — токен (см. скриншот), он понадобится для получения ID чата, в который будем отправлять данные заявки.

Отлично, бот готов. Создаем чат и добавляем в него бота.

  1. Слева в меню Телеграма выбираем «Создать группу».
  2. Пишем название группы, например «Заявки с сайта [название сайта]».
  3. Добавляем бота в созданную группу через поиск.

Затем нужно активировать бота командой /join @uplite_bot. Пишем ее в созданной группе, далее кликаем по имени бота @uplite_bot, и нас перебрасывает на диалог с нашим ботом, где его нужно активировать командой /start.

Теперь необходимо получить ID чата, делается это следующим запросом:

https://api.telegram.org/botXXXXXXXXXXXXXXXXXXXXXXX/getUpdates

Где XXXXXXXXXXXXXXXXXXXXXXX — токен вашего бота, полученный ранее.

Вставляем свой токен и переходим по ссылке, затем снова заходим в чат с нашим ботом и повторно активируем его командой /start, обновляем ссылку и ищем ID чата, он будет выглядеть следующим образом:

Ищем в тексте ID с черточкой — это и есть наш ID чата.

Итак, у нас теперь есть все данные для отправки заявки в чат Телеграма, осталось только настроить в mail.php.

//ОТПРАВКА В ТЕЛЕГРАМ

$token = "ваш_токен";

$chat_id = "id_чата";

$arr = array(

  'Телефон: ' => $wgphone,

  'Страница' => $wgpage,

  'Тема' => $wgdata

);


foreach($arr as $key => $value) {

  $txt .= "<b>".$key."</b> ".$value."%0A";

};


$sendToTelegram = fopen("https://api.telegram.org/bot{$token}/sendMessage?chat_id={$chat_id}&parse_mode=html&text={$txt}","r");

Проверяем – все должно работать 🙂 Теперь у нас есть виджет с различными вариантами отправки заявок, который удовлетворит пожелания большинства заказчиков.

Межтекстовые Отзывы
Посмотреть все комментарии
guest