AJAX форма подписки пользователя с помощью Sendex. Часть 2.

07.06.2018
7751

Реализацию нашего функционала мы начнем с подписки на первом экране. Реализовывать ее будем с помощью компонента Sendex. Для начала нам нужно создать подписку в разделе “Приложения -> Sendex”:

[[*pagetitle:htmlent]]

Отлично! Подписка создана. Сам процесс подписки пользователя будет реализован на AJAX, поэтому нам нужно создать технический ресурс для подписки пользователей, где у нас будет размещен вызов сниппета Sendex. Обычно я создаю подобные ресурсы следующим образом:

[[*pagetitle:htmlent]]

Обязательно установите во всех трех ресурсах флажки “Опубликован” и “скрыть из меню”, а на вкладке “Настройки” снимите флажки “Доступен для поиска” и “Использовать HTML-редактор”. Шаблон же у данных ресурсов должен быть “пустой”. В контентную часть помещаем вызов сниппета Sendex:

[[!Sendex? 
&id=`1`
]]

Где параметр id – это идентификатор нашей рассылки. В анонсе данного курса я писал, что мы будем модернизировать наш сниппет Sendex, так как в таком виде он нам не подходит из-за того, что отдает HTML-код, нам же необходимо, чтобы он отдавал JSON строку, которую мы с вами могли бы легко распарсить с помощью jQuery.

Чтобы это реализовать, я скопировал стандартный сниппет Sendex и назвал его SendexAjax. В видео я подробно рассказал, что мы делали с ним, поэтому здесь я приведу только код данного сниппета:

<?php
/** @var array $scriptProperties */
/** @var Sendex $Sendex */

$output = array();

$Sendex = $modx->getService('sendex','Sendex',$modx->getOption('sendex_core_path',null,$modx->getOption('core_path').'components/sendex/').'model/sendex/',$scriptProperties);
if (!($Sendex instanceof Sendex)) return '';

if (empty($linkTTL)) {$linkTTL = 1800;}

if (empty($id) || !$newsletter = $modx->getObject('sxNewsletter', $id)) {
    $output['success'] = false;
    $output['message'] = $modx->lexicon('sendex_newsletter_err_ns');
}

/** @var sxNewsletter $newsletter */
if (!$newsletter->active && empty($showInactive)) {
	$output['success'] = false;
    $output['message'] = $modx->lexicon('sendex_newsletter_err_disabled');
}

$placeholders = $newsletter->toArray();
$placeholders['message'] = '';
$placeholders['error'] = 0;
if ($modx->user->isAuthenticated($modx->context->key)) {
	$placeholders = array_merge(
		$modx->user->toArray(),
		$modx->user->Profile->toArray(),
		$placeholders
	);
}

$isAuthenticated = $modx->user->isAuthenticated($modx->context->key);

if (!empty($_REQUEST['sx_action'])) {
	$isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';

	$params = $_GET;
	unset($params[$modx->getOption('request_param_alias')]);
	unset($params[$modx->getOption('request_param_id')]);

	switch ($_REQUEST['sx_action']) {
		case 'subscribe':
			if ($isAuthenticated && $modx->user->id) {
				if (!$response = $newsletter->Subscribe($modx->user->id)) {
					$output['success'] = false;
                    $output['message'] = $modx->lexicon('sendex_subscribe_err_email_wrong');
				}
			}
			elseif (!empty($_REQUEST['email'])) {
				$email = htmlentities(strip_tags(urldecode($_REQUEST['email'])));
				$response = $newsletter->checkEmail($email, $modx->user->id, $linkTTL);
				if ($response === true) {
					$output['success'] = false;
                    $output['message'] = $modx->lexicon('sendex_subscribe_err_already');
				}
				elseif ($response === false) {
					$output['success'] = false;
                    $output['message'] = $modx->lexicon('sendex_subscribe_err_email_wrong');
				}
				else {
					$params['hash'] = $response;
					$params['sx_action'] = 'confirm';
					$placeholders['link'] = $modx->makeUrl($modx->resource->id, $modx->context->key, $params, 'full');
					$placeholders['email_body'] = $modx->getChunk($tplActivate, $placeholders);
					$response = $Sendex->sendEmail($email, $placeholders);
					if ($response !== true) {
						$output['success'] = false;
                        $output['message'] = $modx->lexicon('sendex_subscribe_err_email_send');
						
					} else {
					    $params['sx_subscribed'] = 1;
					    $output['success'] = true;
                        $output['message'] = "На ваш почтовый ящик было отправлено письмо со ссылкой, по которой нужно перейти, чтобы подтвердить подписку!";
					}
				}
			}
			else {
				$output['success'] = false;
                $output['message'] = $modx->lexicon('sendex_subscribe_err_email_ns');
			}
			unset($params['email'], $params['hash']);
			break;
		case 'confirm':
			if (!empty($_REQUEST['hash'])) {
				$response = $newsletter->confirmEmail($_REQUEST['hash']);
				$params['sx_confirmed'] = 1;
				unset($params['hash']);
			}
			break;
		case 'unsubscribe':
			if (!empty($_REQUEST['code'])) {
				$response = $newsletter->unSubscribe($_REQUEST['code']);
				$params['sx_unsubscribed'] = 1;
			}
			unset($params['code']);
			break;
	}

	unset($params['sx_action']);
	if (!$isAjax && empty($placeholders['message'])) {
		$modx->sendRedirect($modx->makeUrl($modx->getOption("site_start"), $modx->context->key, $params, 'full'));
	}
}

return json_encode($output);

Теперь в нашем ресурсе нам нужно поменять наименование сниппета на SendexAjax вместо Sendex и получать уже JSON массив.

Чтобы у нас заработала отправка уведомлений, нам необходимо модернизировать HTML-код с формой подписки и добавить туда некоторые моменты, а именно класс, заполнить атрибут action и добавить скрытый параметр sx_action. Код формы у меня получился следующий:

<div class="col-sm-6">
    <div class="wecome-content newsletter-content">
         <h1>Connected With Us. Subscribe For Product Update News</h1>
        <form action="[[~4]]" method="post" class="subscribe-form">
            <input type="hidden" name="sx_action" value="subscribe">
            <input type="text" class="form-control" name="email" placeholder="Enter Tour Email">
            <button type="submit">Subscribe Now</button>
        </form>
    </div>
</div>

Теперь напишем JS обработчик на jQuery в чанк scripts, который позволит нам получать данные с сервера по технологии AJAX. Код обработчика:

$('.subscribe-form').submit(function(e){
        e.preventDefault();
        var msg = $(this).serialize();
        var url = $(this).attr("action");
        $.ajax({
            type: "POST",
            url: url,
            data: msg,
            dataType: "json",
            success: function(data){
                if(data.success){
                    miniShop2.Message.success(data.message);
                }else{
                    miniShop2.Message.error(data.message);
                }
            }
        })
    })

Если вы попытаетесь отправить форму, то в консоли браузер выдаст ошибку из-за того, что у нас не инициализирован miniShop2, поэтому нам с вами необходимо модернизировать код плагина miniShop2 и добавить строку перед словом “break” в событии “OnMODXInit” (примерно 10 строчка):

	$miniShop2->initialize($modx->context->key);

Попробуйте снова отправить форму и увидите, что наши уведомления начали уходить и стала появляться симпатичное окошко со статусами.

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

	$.extend({
      getUrlVars: function(){
        var vars = [], hash;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for(var i = 0; i < hashes.length; i++)
        {
          hash = hashes[i].split('=');
          vars.push(hash[0]);
          vars[hash[0]] = hash[1];
        }
        return vars;
      },
      getUrlVar: function(name){
        return $.getUrlVars()[name];
      }
    });

И напишем обработчик для наших GET-параметров на jQuery в разделе $(document).ready():

	var confirmed = $.getUrlVar('sx_confirmed');
    var unsubscribe = $.getUrlVar('sx_unsubscribed');
    if(confirmed){
        setTimeout(function(){
            miniShop2.Message.success("Ваш email был успешно подтвержден!");
        }, 1000);
    }
    if(unsubscribe){
        setTimeout(function(){
            miniShop2.Message.success("Вы успешно отписались от рассылки!");
        }, 1000);
    }

Полный код чанка scripts получился следующий:

	<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/owl.carousel.min.js"></script>
<script src="assets/js/magnific-popup.min.js"></script>
<script src="assets/js/bootsnav.js"></script>
<script src="assets/js/custom.js"></script>
<script>

    $.extend({
      getUrlVars: function(){
        var vars = [], hash;
        var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
        for(var i = 0; i < hashes.length; i++)
        {
          hash = hashes[i].split('=');
          vars.push(hash[0]);
          vars[hash[0]] = hash[1];
        }
        return vars;
      },
      getUrlVar: function(name){
        return $.getUrlVars()[name];
      }
    });

$(document).ready(function(){
    var confirmed = $.getUrlVar('sx_confirmed');
    var unsubscribe = $.getUrlVar('sx_unsubscribed');
    if(confirmed){
        setTimeout(function(){
            miniShop2.Message.success("Ваш email был успешно подтвержден!");
        }, 1000);
    }
    if(unsubscribe){
        setTimeout(function(){
            miniShop2.Message.success("Вы успешно отписались от рассылки!");
        }, 1000);
    }
    $('.subscribe-form').submit(function(e){
        e.preventDefault();
        var msg = $(this).serialize();
        var url = $(this).attr("action");
        $.ajax({
            type: "POST",
            url: url,
            data: msg,
            dataType: "json",
            success: function(data){
                if(data.success){
                    miniShop2.Message.success(data.message);
                }else{
                    miniShop2.Message.error(data.message);
                }
            }
        })
    })
});
</script>

Таким вот простым образом мы с вами реализовали форму подписки пользователя на новости.

AJAX форма подписки пользователя с помощью Sendex. Часть 2.

0 Число голосов: 6
4
5
1
6

Комментарии ()

  1. Комментарий был удален.
    1. Дмитрий 05 октября 2019, 01:24 # 0
      Что я не правильно прописал? Subscribe Now а вот скрипт
      1. zilog 23 марта 2020, 00:45 # 0
        Привет! Офигенный тутор, спасибо тебе. Я, правда, для получения ссылки get запроса использовал плагин getUrlParam с modx.com, а не jQuery плагин. А всплывашки сделал из alertов bootstrapа.
        1. Sergey 21 января 2021, 14:51 # 0
          Пробовал сделать, сниппет выдает — "[]" — скобки, в журнале ошибок пусто. В чем может быть проблема?
          1. Vlad 04 сентября 2021, 11:43 # 0
            Добрый день. Артём, сделал всё по Вашему уроку. При нажатии на кнопку для отправки данных формы, возникает ошибка — «success»: false, «message»: «Не могу отправить email.» Т.е. не выполняется проверка где-то здесь:
            else {
            	$params['hash'] = $response;
            	$params['sx_action'] = 'confirm';
            	$placeholders['link'] = $modx->makeUrl($modx->resource->id, $modx->context->key, $params, 'full');
            	$placeholders['email_body'] = $modx->getChunk($tplActivate, $placeholders);
            	$response = $Sendex->sendEmail($email, $placeholders);
            	if ($response !== true) {
            	$output['success'] = false;
            	$output['message'] = $modx->lexicon('sendex_subscribe_err_email_send');
            Причём вручную рассылки Sendex проходят, а вот при отправке email через форму — нет. Также данные с других форм фидбэка прекрасно уходят по аяксу, Куда копать, подскажите, пожалуйста.
            1. Петропавловский Артем 04 сентября 2021, 12:03(Комментарий был изменён) # 0
              Смотрите, здесь используется функция
              $Sendex->sendEmail($email, $placeholders);
              Эта функция находится в классе core/components/sendex/model/sendex/sendex.class.php
              Вот она:
              public function sendEmail($email, array $options = array()) {
              		/** @var modPHPMailer $mail */
              		$mail = $this->modx->getService('mail', 'mail.modPHPMailer');
              
              		$mail->set(modMail::MAIL_BODY, $this->modx->getOption('email_body', $options, ''));
              		$mail->set(modMail::MAIL_FROM, $this->modx->getOption('email_from', $options, $this->modx->getOption('emailsender'), true));
              		$mail->set(modMail::MAIL_FROM_NAME, $this->modx->getOption('email_from_name', $options, $this->modx->getOption('site_name'), true));
              		$mail->set(modMail::MAIL_SUBJECT, $this->modx->getOption('email_subject', $options, $this->modx->lexicon('sendex_subscribe_activate_subject'), true));
              
              		$mail->address('to', $email);
              		$mail->address('reply-to', $this->modx->getOption('email_from', $options, $this->modx->getOption('emailsender'), true));
              		$mail->setHTML(true);
              
              		$response = !$mail->send()
              			? $mail->mailer->errorInfo
              			: true;
              		$mail->reset();
              
              		return $response;
              	}
              Следовательно, modPHPMailer не может отправить письмо. Чтобы посмотреть почему, вы можете проверить логи MODX (Управление->Отчеты->Журнал ошибок). Или же вы можете после этой строки:
              if ($response !== true) {
              Написать:
              $modx->log(MODX_LOG_LEVEL_ERROR, $response);
              Тогда в журнале ошибок вы сможете увидеть на что ругается modPHPMailer
              1. manwithawp 17 октября 2022, 01:28(Комментарий был изменён) # 0
                Была такая же ошибка.Вылечил добавлением строчки вначале кода.
                $tplActivate = $modx->getOption('tplActivate',$scriptProperties,'tpl.Sendex.activate');
                Может кому поможет
            2. Vlad 04 сентября 2021, 15:03 # 0
              Спасибо. Разобрался. Много чего сделал, но вроде заработало после того, как прямо указал сниппету &tplActivate
              1. Сергей 16 октября 2021, 10:54 # 0
                Добрый день.Сниппет выдает — "[]" — скобк. В чем может быть проблема? Прочитал комменты, не у меня одного. Может кто подсказать?
                1. Николай 30 января 2022, 01:20 # 0
                  Здравствуйте. Не подскажете, в чем может быть проблема… все сделал по вашему уроку, пересмотрел несколько раз урок, код копировал с вашего блога, на ошибки каждый знак проверил… все работает, письма приходят… НО нет всплывашек (проверьте почту и тд.), может что-то не допонял… что может быть не так, может помимо описанного в уроке вы еще что-то делали? в чем может быть проблема?PS: в js и коде modx я новичок)
                  1. Дмитрий 22 мая 2022, 15:56 # 0
                    А что делать, если нет minishop2? Сайт корпоративный
                    1. Дмитрий 23 мая 2022, 10:01 # 0
                      И для авторизованных выдаёт ошибку, но подписывает.
                      1. Вероника Васильевна Субботина 19 февраля 2023, 20:34 # 0
                        Добрый вечер, Артем! Все делала как вы написали ничего не получается… не пойму откуда взялся у вас minishop2 не рассказываете? Можете за плату мне просто сделать рассылку с помощью Sendex
                        1. Вероника Васильевна Субботина 19 февраля 2023, 20:36 # 0
                          Добрый вечер, Артем. Ничего не смогла сделать по вашей инструкции, не поняла откуда взялся minishop2, не рассказываете? Можно вас просто за плату попросить сделать мне рассылку с помощью Sendex
                          1. Вероника Васильевна Субботина 19 февраля 2023, 20:37 # 0
                            Добрый вечер, Артем. Ничего не смогла сделать по вашей инструкции, не поняла откуда взялся minishop2, не рассказываете? Можно вас просто за плату попросить сделать мне рассылку с помощью Sendex

                            Наши клиенты

                            Многие компании уже доверяют нам. Будьте в их числе!

                            Хотите реализовать проект?

                            Контакты

                            Напишите нам - мы расскажем вам много интересного!


                            Пермь, ул. Крупской 34, офис 510