MODX - Создание email рассылки

Содержание:
  1. Установка компонента Sendex
  2. Создание email шаблона письма
  3. Создание рассылки
  4. Создание ресурса «Email подписка»
  5. Автоматическое формирование тела email рассылки
  6. Настройка cron для запуска email рассылки по расписанию
  7. Пример содержимого email письма (рассылки)
  8. Комментарии

Статья, в которой рассмотрим, как на базе компонента Sendex организовать еженедельную email рассылку писем подписчикам сайта.

Создание автоматической email рассылки для CMS MODX Revolution

Создание email рассылки для MODX Revolution на основе дополнения Sendex будет состоять из следующих основных шагов:

  • установка компонента Sendex;
  • создания email шаблона письма;
  • создания подписки;
  • разработки ресурса, на котором зарегистрированный и анонимный пользователь смогут не только подписаться на email рассылку, но также отписаться от неё;
  • создания php скрипта create.letters.php для автоматического формирования основного содержимого email рассылки и очереди писем для отправки;
  • настройки планировщика cron, который будет запускать в определённые моменты времени файлы create.letters.php и send.php.

Установка компонента Sendex

Установка компонента Sendex осуществляется через поставщика modstore.pro. Если он у вас не установлен, то сначала создайте его. После этого загрузите и установите для CMS MODX Revolution дополнение Sendex.

Создание email шаблона письма

Разрабатывать рассылку начнём с создания шаблона. Он необходим для создания HTML структуры (email шаблона) письма. В качестве имени зададим ему, например, значение SendexTemplate.

Содержимое шаблона (пример):

<table style="background-color: #f1f1f1; width:100%; font-family:-apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;" align="center" width="100%" border="0" cellpadding="0" cellspacing="0">
  <tbody>
    <tr>
      <td align="center" style="vertical-align:top;padding:30px 0;text-align:center">
        <table style="text-align:left;width:680px;margin:0 auto;font-size:14px;border-spacing:0px">
          <tbody>
            <tr>
              <td bgcolor="#fff" style="padding: 15px;">
                <font color="#777" style="font-size:18px">[[+newsletter.name]] ([[+phx:input=`now`:strtotime:date=`%d.%m.%Yг.`]])</font>
              </td>
            </tr>
            <tr><td height="25"></td></tr>
            <tr>
              <td bgcolor="#fff" style="padding: 15px;">
                [[+newsletter.description]]
              </td>
            </tr>
            <tr><td height="25"></td></tr>
            <tr>
              <td bgcolor="#fff" style="padding: 20px 15px; color: #777; font-size: 14px;">
                <p>© 2017 Мой сайт.</p>
                <p style="font-size: 12px;">Это сообщение было отправлено на [[+subscriber.email]] потому, что вы подписались на еженедельную рассылку. Данное письмо не требует ответа.</p>
                <p style="font-size: 12px;">Если вы не хотите больше получать письма от нас, то щелкните <a href="[[~10?scheme=`full`&sx_action=`unsubscribe`&code=`[[+subscriber.code]]`]]" target="_blank">здесь</a>.</p>
              </td>
            </tr>
          </tboy>
        </table>
      </td>
    </tr>
  </tbody>
</table>

Назначение ссылки и плейсхолдеров в содержимом шаблона SendexTemplate:

  • [[+newsletter.name]] - название подписки;
  • [[+newsletter.description]] - описание (основное содержимое) подписки;
  • [[+subscriber.email]] - email адрес подписчика;
  • ~10 - формирует ссылку на 10 ресурс сайта (этот ресурс, а точнее сниппет Sendex, расположенный в нём, будет осуществлять отписку от рассылки, если конечно пользователь перейдёт по ней);
  • [[+subscriber.code]] - код подписчика.

Создание рассылки

Для создания рассылки откроем в админке MODX страницу Sendex (Приложения -> Sendex). Переключимся на вкладку "Подписки" и нажмём на кнопку "Создать".

MODX Sender - Создание подписки

В диалоговом окне "Создать подписку" заполним поля формы следующими значениями:

  • Название - Информационная рассылка;
  • Шаблон - SendexTemplate;
  • Тема письма - Мой сайт - Еженедельная информационная рассылка;
  • Ответный email - no-reply@mysite.ru;
  • Исходящий email - no-reply@mysite.ru;
  • Отправитель - Мой сайт.

Поле "Описание" заполнять не будем. Его наполнение будем осуществлять с помощью php скрипта create.letters.php. Данный скрипт будем запускать с помощью планировщика cron раз в неделю.

MODX Sender - Отображение созданной подписки (имеющей id = 1) в таблице рассылок

Создание ресурса «Email подписка»

Создадим в админке MODX Revolution ресурс (pagetitle - Email подписка).

В содержимое ресурса поместим вызов 2 сниппетов:

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

Сниппет Sendex

Сниппет Sendex осуществляет подписку пользователя на рассылку (в данном случае ту, которая имеет идентификатор 1), а также отписку от неё.

Подписку на рассылку, а также отписку от неё авторизированный пользователь осуществляет с помощью щелчка по кнопке.

MODX Sender - Форма подписки на email рассылку для авторизированного пользователя

Анонимный же пользователь осуществляет подписку через ссылку в письме. Для получения письма он должен ввести свой email адрес в форму подписки и нажать на кнопку «Подписаться».

MODX Sender - Форма подписки на email рассылку для анонимного (не авторизированного) пользователя

Отписка от рассылки также осуществляется с помощью ссылки, которую, например можно расположить в футере письма. Если анонимный пользователь больше не захочет получать еженедельную информационную рассылку, то ему будет достаточно просто перейти по ней. Идентификация подписчика осуществляется по коду.

Настройка вывода форм, связанных с подпиской, сниппет Sendex осуществляет с помощью параметров:

  • tplSubscribeGuest - чанк (по умолчанию tpl.Sendex.subscribe.guest), содержащий форму, с помощью которой анонимный пользователь может подписаться на рассылку.
  • tplActivate - чанк (по умолчанию tpl.Sendex.activate), содержащий email шаблон, на основании которого будет формироваться письмо анонимному пользователю. Основное содержимое письма – это ссылка, по которой ему необходимо перейти для того, чтобы подтвердить подписку.
  • tplSubscribeAuth – чанк (по умолчанию tpl.Sendex.subscribe.auth), содержащий форму подписки, которая будет показываться авторизированному пользователю;
  • tplUnsubscribe – чанк (по умолчанию tpl.Sendex.unsubscribe), содержащий форму, посредством которой авторизированный пользователь может отписаться от рассылки.

При необходимости вы можете настроить содержимое каждого чанка. Но лучше это делать не в исходных чанках, а в их копиях, которые затем указать сниппету с помощью соответствующих параметров:

Например:

[[!Sendex?
  &id=`1`
  &tplSubscribeAuth=`tplSendexSubscribeAuth`
  &tplSubscribeGuest=`tplSendexSubscribeGuest`
  &tplUnsubscribe=`tplSendexUnsubscribe`
  &tplActivate=`tplSendexActivate`
]]

Сниппет SendexEventTracking

Сниппет SendexEventTracking предназначен для отображения на странице информационных сообщений, связанных с email подпиской.

Вывод того или иного сообщения зависит от наличия в составе URL одного из следующих параметров: sx_subscribed, sx_confirmed, sx_unsubscribed.

Код сниппета SendexEventTracking:

<?php
$output = '';
$subscribed = $modx->getOption('subscribed', $scriptProperties, 'tplSendexEventSubscribed');
$confirmed = $modx->getOption('confirmed', $scriptProperties, 'tplSendexEventConfirmed');
$unsubscribed = $modx->getOption('unsubscribed', $scriptProperties, 'tplSendexEventUnsubscribed');
if ($_GET['sx_subscribed']) {
  $output = $modx->getChunk($subscribed);
}
if ($_GET['sx_confirmed']) {
  $output = $modx->getChunk($confirmed);
}
if ($_GET['sx_unsubscribed']) {
  $output = $modx->getChunk($unsubscribed);
}
return $output;

Все информационные сообщения хранятся в чанках (по умолчанию): tplSendexEventSubscribed, tplSendexEventConfirmed, tplSendexEventUnsubscribed.

Код чанка tplSendexEventSubscribed (пример):

<div class="alert alert-danger">На указанный почтовый ящик отправлено письмо, содержащее ссылку. Перейдите по ссылке для подтверждения email адреса, на который будут высылаться раз в неделю новые статьи.</div>

Код чанка tplSendexEventConfirmed (пример):

<div class="alert alert-danger">Вы успешно подписаны на еженедельную email рассылку сайта.</div>

Код чанка tplSendexEventUnsubscribed (пример):

<div class="alert alert-danger">Вы успешно отписаны от рассылки новых статей сайта.</div>
MODX Sender - Отображения информационного сообщения о том что указанный email адрес необходимо подтвердить, чтобы на него получать рассылку

Автоматическое формирование тела email рассылки

Формировать тело рассылки будем выполнять автоматически с помощью php файла. Для этого создадим файл create.letters.php, например, в директории cron (/core/components/sendex/cron/) со следующим содержимым:

<?php
require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');

// id раздела, в котором расположены статьи
$parent = array(5,6,7);
// создадим запрос на выборку новых статей, расположенных в указанных разделах (дата публикации не позже 7 дней)
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => $parent
));
// ограничим выборку 5 элементами
$query->limit(5);
// получим статьи
$resources = $modx->getCollection('modResource', $query);

$output = '';
// переберём статьи и сформируем ответ
foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  $description = $resource->get('description');
  $url = $modx->makeUrl($id,'','','https');
  // получим tv поле image (id=2)
  $image = $modx->getObject('modTemplateVarResource',array( 'tmplvarid' => 2, 'contentid' => $id ));
  if (is_object($image)) {
    $image = 'http://mysite.ru/assets/images/'.$image->get('value');
  } else {
    $image = '';
  }
  $output .= $modx->getChunk('tpl.newsletter.article',array(
    'pagetitle' => $pagetitle,
    'description' => $description,
    'url' => $url,
    'image' => $image
  ));
}
$count = count($resources);

// не будем формировать очередь, если количество новых статей равно нулю
if ($count==0) {
  exit();
}

// формируем очередь (создаём письма для отправки подписанным пользователям)
$modx->addPackage('sendex', MODX_CORE_PATH . 'components/sendex/model/');
/** @var sxNewsletter $newsLetter */
if ($newsLetter = $modx->getObject('sxNewsletter', 1)) {
  $newsLetter = $modx->getObject('sxNewsletter', 1);
  $newsLetter->set('description',$output);
  $newsLetter->save();
  $response = $newsLetter->addQueues();
}

exit();

Пример чанка, который будет использовать для оформления каждой статьи в письме (tpl.newsletter.article):

<tr>
  <td bgcolor="#fff" style="padding: 15px;">
    <table border="0" cellpadding="0" cellspacing="0" align="left" width="100%">
      <tbody>
        <tr>
          <td width="12" valign="middle" style="padding:10px 0;">
            <span style="display:block;border-left:5px solid #2ecc71">
              <font style="font-size:20px"> </font>
            </span>
          </td>
          <td valign="middle" style="padding: 10px 0;">
            <font color="#2ecc71" style="font-size:20px">[[+pagetitle]]</font>
          </td>
        </tr>
      </tbody>
    </table>
  </td>
</tr>
<tr>
  <td valign="top" bgcolor="#fff">
    <table border="0" cellpadding="0" cellspacing="0" align="left" style="width:100%;">
      <tbody>
        <tr>
          <td valign="top">
            <img src="[[+image]]" alt="[[+pagetitle]]" style="max-width: 100%;">
          </td>
        </tr>
        <tr>
          <td valign="top" style="padding: 15px;">
            <font color="#777" style="font-size:14px">[[+description]]</font>
          </td>
        </tr>
        <tr>
          <td align="right" style="padding: 5px 15px 10px 0px;">
            <a href="[[+url]]" target="_blank">
              <font color="#2ecc71" style="font-size:14px">
              Читать далее...</font></a>
          </td>
        </tr>
      </tbody>
    </table>
  </td>
</tr>
<tr><td height="25"></td></tr>
MODX Sender - Пустая очередь писем (до запуска файла create.letters.php) MODX Sender - Письма добавленные в очередь для отправки (после запуска файла create.letters.php)

Настройка cron для запуска email рассылки по расписанию

Заключительное действие - это добавление в программу-планировщик cron двух заданий для запуска их в определённое время с определённой периодичностью.

Например:

  1. файл create.letters.php (формирование писем и додавление их в очередь) - например, каждый четверг в 6 часов утра (0 6 * * 4);
  2. файл send.php (отправка писем) - например, каждый четверг, начиная с 7 часов утра (*/12 7-9 * * 4).

Если подписчиков много, то письма можно отправлять небольшими порциями (например, по 50 штук) каждые 5 минут (*/12) в течение 3 часов (7-9). Файл send.php необходимо запускать после выполнения файла create.letters.php.

Содержимое файла send.php:

<?php

require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/config.core.php';
require_once MODX_CORE_PATH . 'config/' . MODX_CONFIG_KEY . '.inc.php';
require_once MODX_CONNECTORS_PATH . 'index.php';

$modx->addPackage('sendex', MODX_CORE_PATH . 'components/sendex/model/');

$q = $modx->newQuery('sxQueue');
$q->limit($modx->getOption('sendex_queue_limit', null, 50, true)); // 50 - количество писем, отправляемых за один раз

$queue = $modx->getCollection('sxQueue', $q);
/** @var sxQueue $email */
foreach ($queue as $email) {
	$email->send();
}
Пример создания новой задачи для cron с помощью панели управления виртуальным хостингом

Пример содержимого email письма (рассылки)

После отправки рассылки, каждый подписанный пользователь получит на свой адрес письмо, содержащий материал собранный create.letters.php.

Пример содержимого еженедельной email рассылки

Комментарии: 95

Максим
Максим
Александр, здравствуйте. Сделал рассылку по вашей методике, за исключением create.letters.php. Так как для стандартной работы это не нужно (ИМХО). Все сделал так, как Вы описываете в данной статье. Компонент Sendex установлен. Шаблон письмо создан. Подписка так же создана (id=1). Вывожу как Вы и написали — [[!Sendex? &id=`1`]]. Компонент выводиться на фронт. Но есть одна проблемка, над которой ломаю голову. Когда ввожу почту (аноним) и нажимаю на кнопку «Подписаться!», то выше формы постоянно появляется сообщение — Не могу отправить email.. И указанная почта не появляется в списке подписчиков! Вот ссылка на изображение — itchief.ru/assets/uploadify/b/e/a/bea1dfe464e6fd128c98c0bcdc8709bd.jpg.
Скажите, пожалуйста, что я могу делать не так? Спасибо!
Людмила
Людмила
Благодарю за сайт и статью! Скажите, почему выходит ошибка при cron-запуске create.letters.php:

Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283

в 283 строке действительно есть строка с квадратными скобками: private $loggedDeprecatedFunctions = [];

но ведь это стандартная поставка modx: htdocs\www\core\model\modx\modx.class.php

Начало create.letters.php как у Вас:

require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))). '/config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
Александр Мальцев
Александр Мальцев
Файл «create.letters.php» расположен в «/core/components/sendex/cron/». Для того что из него добраться до «config.core.php» нужно 5 раз использовать dirname. На следующей строчке подключается «modx.class.php», который расположен на хостинге по адресу «MODX_CORE_PATH.'model/modx/modx.class.php'».
Людмила
Людмила
Благодарю за ответ, но если я подключаю только
require_once dirname(dirname(dirname(dirname(dirname(__FILE__))))). '/config.core.php';

то выходит сообщение:

Class 'modX' not found in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/components/sendex/cron/create.letters.php on line 5.

понятно, что не подключен modx.class.php.
Людмила
Людмила
а если я подключаю require_once MODX_CORE_PATH.'model/modx/modx.class.php';

то парсер конкретно говорит не об ошибке create.letters.php, а об ошибке modx.class.php. Но это же стандартный класс, я в нём ничего не меняла, как может быть ошибка в нём?

Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283
Людмила
Людмила
Кстати, send.php выдает точно такую же ошибку…

Parse error: syntax error, unexpected '[' in /home/host1604701/oartemi-slovo.ru/htdocs/www/core/model/modx/modx.class.php on line 283

Виталий
Виталий
Проверьте версию PHP, на которой работает ваш cron на хостинге. Она часто отличается от той, которая установлена для сайта, у меня, например была 5.2. и тоже были ошибки
Людмила
Людмила
Ура! Решено! Был на cron PHP 5.3, а на сайте PHP 5.6, всё решили на хостинге. Благодарю! Слава Богу!
Людмила
Людмила
Здравствуйте! На вкладке Sendex «Очередь писем», где «Добавить письма рассылки в очередь», я выбираю свою подписку, и сразу формируются письма подписчикам. Потом я нажимаю «Отправить всё», письма уходят, но уходит пустой шаблон, без материалов, которые должен сформировать create.letters.php. Почему не срабатывает create.letters.php? Он на месте.
Александр Мальцев
Александр Мальцев
Здравствуйте! «create.letters.php» нужен для программного создания писем. Он к ручному формированию и тем более к шаблону, который для этого используется вообще никакого отношения не имеет.
Людмила
Людмила
Благодарю, поняла.
Виталий
Виталий
Здравствуйте, Александр!
Подскажите, пожалуйста, как правильно написать условие для
$parent =
, если нужно выбрать несколько разделов, некоторые из которых еще и контейнеры (указать глубину).
Например, разделы 1,3,5,7, из которых 3 и 5 содержат подразделы.
Про
$parent = $modx->getChildIds(2,3);
прочитал, а как поступить если таких парентов несколько, и плюс обычные разделы?
Спасибо за Ваш сайт, и за Ваш труд!
Александр Мальцев
Александр Мальцев
Здравствуйте!
В PHP имеется функция array_merge с помощью которой слить несколько массивов в один.
Виталий
Виталий
Благодарю!
Людмила
Людмила
Добрый день! Благодарю за сайт, обычно так всё понятно и хорошо написано. Только сейчас немного запуталась. Почему может получиться такое: copy.oartemi-slovo.ru/email-podpiska?
Вроде всё делаю по инструкции.
Александр Мальцев
Александр Мальцев
Добрый день! Спасибо за отзыв! Страница должна иметь обычный шаблон, т.е. тот который имеют другие страницы у вас на сайте. Может быть вы в качестве шаблона выбрали «Sendex»? «Sendex» используется в качестве шаблона только для email сообщений, его не нужно устанавливать для страниц сайта.
Людмила
Людмила
Благодарю, простите за невнимательность.
_Iris_
_Iris_
Александр, здравствуйте!
Спасибо за статью!
Подскажите, пожалуйста, а можно ли с помощью Sendex отправлять письма пользователям, если их ресурс (где пользователь автор) опубликован и оповещать их, если приближается дата отмены публикации?
Для доски объявлений
Александр Мальцев
Александр Мальцев
Здравствуйте, конечно можете. Для этого напишите соответствующую логику в «create.letters.php» и настройки cron, например, раз в час. Cron будет запускать на выполнение скрипт «create.letters.php» и формировать письма на отправку.
_Iris_
_Iris_
Спасибо за ответ! А не подскажете, как задать условие, чтобы письмо отправлялось именно автору?
Понимаю, что надо через createdby делать
_Iris_
_Iris_
Вот так вот не работает
$user = $modx->getObject('modUser',$userId);
$query = $modx->newQuery('modResource', array(
  'published:<>' => empty,
  'parent:IN' => $parent,
  'createdby:' => $user,
));
Александр Мальцев
Александр Мальцев
Конечно, работать не будет.
Знак «не равно» записывается так:
'name:!=' => 'Тимур', /* не равно */
В поле published хранится 1 или 0. Если published равно 1, то это значит, что ресурс опубликован. В createdby хранится id пользователя (число).

_Iris_
_Iris_
Спасибо большое, лексика у меня страдает))
Только с пользователем не понятно, как по id пользователя формировать рассылку? чтобы только автору приходило письмо
Александр Мальцев
Александр Мальцев
Просто не вижу смысла здесь использовать Sendex. Он необходим чтобы пользователь мог подписаться на рассылку, или отписаться от неё, если он больше не хочет получать информационные сообщения.
Если вам это не нужно, то просто используйте modMail, который идёт вместе с MODX Revolution.
Пример, как его использовать:
$message = $modx->getChunk('myEmailTemplate');

$modx->getService('mail', 'mail.modPHPMailer');
$modx->mail->set(modMail::MAIL_BODY,$message);
$modx->mail->set(modMail::MAIL_FROM,'me@example.org');
$modx->mail->set(modMail::MAIL_FROM_NAME,'Johnny Tester');
$modx->mail->set(modMail::MAIL_SUBJECT,'Check out my new email template!');
$modx->mail->address('to','user@example.com');
$modx->mail->address('reply-to','me@xexample.org');
$modx->mail->setHTML(true);
if (!$modx->mail->send()) {
    $modx->log(modX::LOG_LEVEL_ERROR,'An error occurred while trying to send the email: '.$modx->mail->mailer->ErrorInfo);
}
$modx->mail->reset();
_Iris_
_Iris_
Александр, спасибо за совет! Попробую этот вариант!
Nik
Nik
Доброго дня Александр! У меня вопрос о компонентах Sendex и bxSender. Второй платный, и более функциональный, и подкупает тем что есть статистика по письмам, отслеживание прочтения писем. Но хотелось бы услышать мнение профессионального человека, вы пользовались bxSender? Сильно ли данный компонент грузит систему? И насколько сложная там настройка после установки, по сравнению с Sendex? Если не пользовались, то вопрос конечно же исчерпан.
Автор компонента почему-то перестал отвечать на комментарии (modx.pro)
Александр Мальцев
Александр Мальцев
Привет! Не знаю, не пользовался. Если нужно для аналитики, то мне, кажется, лучше просто прикрутить utm метки к рассылкам, а потом всё это дело анализировать в Google Analytics или Яндекс Метрике. Как по мне, то это всё лучше анализировать в одном месте, чем на какой-то странице в админке MODX. Также эти utm метки можно привязать и к ссылкам, например, размещаемых в социальных сетях, а потом всё это смотреть в одном месте. Но, в bxsender кроме аналитики есть ещё много других плюшек, если они нужны, то можете рассмотреть вопрос о его покупке. У меня опыта работы с этим компонентом нет. На странице в магазине есть видео как его настроить, думаю поэтому поводу проблем не должно возникнуть.
Nik
Nik
Благодарю! Вариант с utm метками отличное решение! в принципе пока больше ничего и не надо в ближайшее время
Роман
Роман
Добрый день.

Создал группу пользователей Sendex, в настройках minishop2 указал, что бы все новые пользователи добавлялись в эту группу.

Создал ресурс отписки от рассылки — в письме получавшему будет ссылка. Перешел, отписался.

Но как указать, что бы когда пользователь отписывается исключался из этой группы?

Смысл в том, пользователь делая заказ на сайте попадает в группу рассылки, а если не хочет получать её то нажимает ссылку в письме и исключается из группы. В Sendex нет инструментов по выбору пользователей для рассылки, или по одному всех подряд или группу, но отправлять пользователю который отписался от рассылки не правильно.

Прошу помощи.
Александр Мальцев
Александр Мальцев
Добрый!
Методы Sendex (в том числе и метод отписывающий пользователя от рассылки) находятся в файле «\core\components\sendex\model\sendex\sxnewsletter.class».
В метод unSubscribe вам необходимо дополнительно добавить код для удаления пользователя из группы.
Роман
Роман
Александр, будет большой наглостью, если я вас попрошу привести пример кода, как это должно выглядеть? Самостоятельно не справлюсь.
Александр Мальцев
Александр Мальцев
Пример:
public function unSubscribe($code) {
  if ($subscriber = $this->xpdo->getObject('sxSubscriber', array('code' => $code))) {
    // получаем id пользователя
    $userId = $subscriber->get('user_id');
    // получаем пользователя
    $user = $this->xpdo->getObject('modUser', array('id' => $userId));
    // если он есть, то удаляем
    if (is_object($user)) {
      $user->remove();
    }
    return $subscriber->remove();
  }
  return false;
}
Роман
Роман
Указал удаление группы, но из группы не удаляется. Я не правильно понял, что нужно?
2 — это ID этой группы
public function unSubscribe($code) {
	if ($subscriber = $this->xpdo->getObject('sxSubscriber', array('code' => $code))) {
		// получаем id пользователя
		$userId = $subscriber->get('user_id');
		// получаем пользователя
		$user = $this->xpdo->getObject('modUser', array('id' => $userId));
		// если он есть, то удаляем
		if (is_object($user)) {
			$user->leaveGroup(2);
			$user->remove();	
		}
		return $subscriber->remove();
	}

	return false;
}
Роман
Роман
Видимо закешировалось, вот так заработало

public function unSubscribe($code) {
	  if ($subscriber = $this->xpdo->getObject('sxSubscriber', array('code' => $code))) {
		// получаем id пользователя
		$userId = $subscriber->get('user_id');
		// получаем пользователя
		$user = $this->xpdo->getObject('modUser', array('id' => $userId));
		// если он есть, то удаляем
		if (is_object($user)) {
			$user->leaveGroup('Sendex');
		}
		return $subscriber->remove();
	  }
	  return false;
	}
Женёк
Женёк
Добрый день!
Можно ли сделать так, чтобы когда добавляется новость на сайт, то сразу рассылка была автоматически?
Александр Мальцев
Александр Мальцев
Добрый! Например, это можно выполнить так. Создать плагин на событие OnDocPublished. Данное событие возникает при публикации ресурса через контекстное меню. В данном плагине создать код, как это реализовано в файле create.letters.php. Отправку писем можно оставить как в статье, т.е. посредством cron; только в качестве интервала для вызова файла send.php установить интервал каждые 5 минут.
Слава
Слава
Все впринцыпе получилось все работает, но вопрос в другом. Я собирался просто сделать рассылку, базу с имейлами купил) как мне добавить 3 тыс имейл адресов для рассылки?
Arhivar
Arhivar
А я написал такой скрипт, который базу закачивает, использовал библиотеку phpExcel и статью «Программное создание пользователей для modx revo»!

Вот ссылки на инфу, которой пользовался для написания:
r-band.ru/how-to/chtenie-faylov-excel-na-php-osnovnye-metody-klassa-phpexcel.html
www.createit.ru/blog/modx/2012/programmatically-creating-users
Могу скрипт продать 3000р))
Андрей
Андрей
скажите а как очистить очередь писем после отправки?
письма формируются, отправляются, но остаются в очереди и по следующему запуску скрипта отправки писем снова уходят.
Александр Мальцев
Александр Мальцев
Очистить очередь можно так:
$modx->addPackage('sendex', MODX_CORE_PATH . 'components/sendex/model/');
// очистка очереди Sendex
$q = $modx->newQuery('sxQueue');
$queue = $modx->getCollection('sxQueue', $q);
foreach ($queue as $email) {
    $email->remove();
}
Андрей
Андрей
Спасибо, отличная статья!
Подскажите как лучше сделать рассылку, где будет выборка по нескольким родителям, но для каждого из них будет свой шаблон?
Вижу 2 варианта:
1. create.letters.php сделать еще одну выборку, но тогда там нужно формировать подзаголовки для каждой выборки, что мне кажется не очень красиво
2. прописать 2 или больше подзаголовка в шаблоне SendexTemplate, но тогда я не понимаю как быть со скриптом create.letters.php он как я понял формирует и все в одно место выдает
Александр Мальцев
Александр Мальцев
Спасибо!
Можно просто написать условие:
...
$parent = $resource->get('parent');
...
if ($parent == 5) {
  $tpl_newsletter = 'tpl.newsletter.article';
} else {
  $tpl_newsletter = 'tpl.newsletter.article2';
}
$output .= $modx->getChunk($tpl_newsletter, array(
  'pagetitle' => $pagetitle,
  ...
Андрей
Андрей
что-то не понял как это сработает…
исходя из кода в зависимости от родителя будет выбран тот или иной шаблон, а мне нужно чтобы были использованы оба шаблона в одной рассылке для $parent == 5 tpl.newsletter.article, а для $parent == 6 — tpl.newsletter.article2
то есть идет текст рассылки
<h2>Новости</h2>
новости выводятся по одному шаблону
<h2>Статья</h2>
шаблон для статей
<h2>Фотки</h2>
шаблон для фоток
Александр Мальцев
Александр Мальцев
Не так понял. Тогда нужно создать шаблоны для раздела «Новости», «Статья» и «Фотки». И сформировать сначала их. После этого их передать в конечный шаблон (чанк).
Например:
// получаем новости
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => array(5,6);

));
$query->limit(5); // ограничим выборку 5 элементами
$resources = $modx->getCollection('modResource', $query);
$output_news = '';
foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  ...
  $output_news.= $modx->getChunk('tpl.newsletter.news',array(
    'pagetitle' => $pagetitle,
    ...
  ));
}

// получаем статьи
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => array(7,8);

));
$query->limit(5); // ограничим выборку 5 элементами
$resources = $modx->getCollection('modResource', $query);
$output_articles = '';
foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  ...
  $output_articles .= $modx->getChunk('tpl.newsletter.article',array(
    'pagetitle' => $pagetitle,
    ...
  ));
}

// получаем фотки
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => array(9,10,11);

));
$query->limit(5); // ограничим выборку 5 элементами
$resources = $modx->getCollection('modResource', $query);
$output_photos = '';
foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  ...
  $output_photos .= $modx->getChunk('tpl.newsletter.photo',array(
    'pagetitle' => $pagetitle,
    ...
  ));
}

// формируем конечный результат
$output_photos = $modx->getChunk('tpl.newsletter',array(
  'news' => $output_news,
  'articles' => $output_articles,
  'photos' => $output_photos,
));
Содержимое чанка tpl.newsletter:
<h2>Новости</h2>
[[+news]]
<h2>Статья</h2>
[[+articles]]
<h2>Фотки</h2>
[[+photos]]
Ну, соответственно содержимое чанков tpl.newsletter.news, tpl.newsletter.article и tpl.newsletter.photo формируете так как это необходимо.
Андрей
Андрей
Спасибо, то что нужно!
А еще вопрос — как я понимаю в текущем варианте идет выборка с глубиной 0? а как добавить глубины выборки например 5?
пробовал
$parent = array(281,7);

$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => $parent,
  'depth' => '5'
));
и всяие
'depth:=' => '5'
'depth:IN' => '5'
и тп — ничего не работает…
Андрей
Андрей
сам нашел решение — нужно глубину поиска переложить на этапе определения родителей
$parent = $modx->getChildIds(281,3);
где первая цифра id раздела, вторая — глубина поиска наследников с таким учетом, чтобы их дети и были нужны в выборке.
надеюсь понятно объяснил, может кому пригодится)
Роман
Роман
Спасибо за статью!

Скажите как можно организовать подписку не перезагружая страницу? Проблема в том, что форма с подпиской находится почти в самом низу страницы, а она не маленькая! Ситуация: ты вводишь свой e-mail страница перезагружается и вообще не понятно что происходит!?

В идеале, перезагружается этот блок и выводится сообщение из снипета SendexEventTracking вместо этой формы! Можно ли такое сделать? Если как, то куда смотреть, как организовать?

Спасибо!
Александр Мальцев
Александр Мальцев
Можно, но не в рамках этой инструкции. Возьму на заметку. Чтобы это сделать необходимо использовать AJAX.
miami
miami
Александр, добрый день!
Подскажите, как реализовать в
$query = $modx->newQuery('modResource', array(
'publishedon:>=' => strtotime('-7 days'),
'parent:IN' => $parent
));

что бы было равно сегодняшней дате.

'publishedon:==' => сегодня,

Идея: Создал статьи и выставил дату публикации на будущее (каждый четверг). Скрипт должен проверить в четверг найти все статьи созданные в этот день и сформировать очередь.
Сейчас он формирует все новости, ограничивается только $query->limit(5);

Надеюсь на Вашу помощь.
Александр Мальцев
Александр Мальцев
Здравствуйте!
Все варианты условий можно посмотреть на этой странице. Они расположены в пункте, который начинается с текста «xPDOQuery.where...».
Знак «равно» задаётся так:
(1 способ)
'publishedon' => mktime(),
(2 способ)
'publishedon:=' => mktime(),
В вашем случае неправильно задавать такое условие, т.к. дата, скорее всего включает в себя ещё и время.
Необходимо, для выбора ресурсов с текущей датой, использовать следующее:
'publishedon:>=' => mktime(0,0,0),
'publishedon:<=' => mktime(23,59,59),
miami
miami
Спасибо, выручили.
Не подскажите еще по одному вопросу.
Sendex останавливает работу если адрес не верный или не существующий, и приходиться запускать заново удаляя из таблицы проблемный емейл.
Может возможно перепрыгивать проблемные мейлы и отсылать дальше.
Как возможно решить этот вопрос?
Александр Мальцев
Александр Мальцев
Нет, никаких проблем не должно быть. Просто это письмо не отправиться, оно не должно влиять на другие.
miami
miami
Странно, вот прямо сейчас не хочет отправлять письма, просто стоит. Я думал при проблемных мейл он застревает т.к. в
$q->limit($modx->getOption('sendex_queue_limit', null, 50, true));
сейчас стоит 2.
При лимите 100 он не плохо все отправил, но мейл не любит таких.
По каким причинам еще он может просто застревать?
P.S.: В ручную по одному письму отправляет. Через send.php и cron не хочет. На той недели отправлял но запинался на проблемных.
miami
miami
Поставил лимит 5 отправляет только 2 письма.
3 видимо проблемные адреса, если сейчас встретит еще 2 проблемных работа рассылки остановится.
Александр Мальцев
Александр Мальцев
Тогда необходимо изменить часть скрипта send.php.
foreach ($queue as $email) {
    $email->send();
}
А именно заменить вышеприведённый блок кода на этот:
foreach ($queue as $email) {
    if ($email->send()!==true) {
        $email->remove();
    }
}
Sergey
Sergey
Спасибо, за статью. Подскажите пожалуйста, как лучше реализовать, чтобы подписчики сразу становились пользователями «Аноним»? Нужно администрировать подписчиков между рассылками.
Александр Мальцев
Александр Мальцев
Любой не авторизированный пользователь на MODX — уже аноним. Подписчики есть в базе, можете просто создать страничку и администрировать их на ней.
Sergey
Sergey
В Sendex есть анонимы, которые подписались через сайт, но перенести их в другую рассылку нельзя, т.е. на кнопке «Добавить пользователя» их нет
s1.bild.me/bilder/110417/4942049screenshot_2017-12-05_005.png
daddydj
daddydj
Отличная статья. Все понятно и доступно.
Возник вопрос, а выборка для еженедельной отправки делается среди новых ресурсов?
Т.е. он может на момент запуска скрипта посмотреть что нового публиковалось в какой-то категории и отправить это в рассылку? Как такое можно реализовать?

И второй вопрос, возможно ли, чтоб при добавлении статьи автоматически происходила отправка, допустим, первых двух абзацев на почту подписчикам с кнопкой «Подробнее»? Как связать sendex со статьями, чтоб он подхватывал картинку из ресурса и текст контента?
Спасибо.
Александр Мальцев
Александр Мальцев
Спасибо.
Да, среди новых (на момент запуска скрипта, выбираются только те ресурсы, которые имеют дату публикации не позже 7 дней). Разделы, из которых это необходимо осуществить настраиваются с помощью переменой $parent.
Для решения второго вопроса, нужно создать плагин на событие OnDocPublished. В обработчике этого события написать код, подобный тому, который приведён в файлах create.letters.php и send.php.
daddydj
daddydj
Что-то все по статье делаю, но выборка не происходит. На почту приходит пустое письмо, причем шаблона Sendex Template и все.
Скрипт из панели Cron на Beget пробовал вручную запускать, тоже ничего не происходит. При том, что ресурсы, перечисленные в Parent младше 7 дней давности.

И еще, если имя TV картинки отличается от image, его везде надо переписать или достаточно только в теле шаблона tpl.newsletter.article?

И что делать с send.php? Судя по статье Cron должен стартовать только первый скрипт? Или создать задания надо на оба файла?
Александр Мальцев
Александр Мальцев
Если что-то не получается с выборкой, то попрубуйте её сначала создать на отдельной странице.
Выбор TV картинки в скрипте выполняется по id, т.е. имя TV не используется.
В примере id TV имеет значение 2:
'tmplvarid' => 2
Снчала должен запускаться скрипт create.letters.php. Он формирует письма и добавляет их в очередь. После него send.php. Он отправляет их.
daddydj
daddydj
все так и есть. ID поля совпадает с ID tv-поля с картинкой. Да и само письмо не формируется почему-то из чанка шаблона. В самом Sendex формируются письма, когда для отправки выбираю единственно созданную рассылку(по примеру). И формируются письма по кол-ву подписчиков. И при отправке письмо приходит пустое в оформлении шаблона Sendex Template. Два раза перепроверил последовательность действий по уроку, пока не разобрался, в чем дело. Modx Revo 2.6.0

Категории новостей с ресурсами в виде коллекции.
Роман
Роман
Как выборку создать на отдельной странице?

п.с. тоже не получается передать TV в тело письма (((
Александр Мальцев
Александр Мальцев
Тут вроде бы всё просто.
Для этого создаём php-файл, например, «letters.php» в корне сайта:
<?php

require_once 'config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');

$pdoTools = $modx->getService('pdoTools');

$output = '';

$parent = array(5,6,7);
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => $parent
));
$query->limit(5);
$resources = $modx->getCollection('modResource', $query);

$count = count($resources);

if ($count == 0) {
  exit();
}

foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  $description = $resource->get('description');
  $url = $modx->makeUrl($id,'','','https');
  $image = $modx->getObject('modTemplateVarResource',array( 'tmplvarid' => 2, 'contentid' => $id ));  
  if (is_object($image)) {
    $image = 'http://mysite.ru/assets/images/'.$image->get('value');
  } else {
    $image = '';
  }
  $output .= $pdoTools->getChunk('@FILE chunks/tpl.newsletter.article',array(
    'pagetitle' => $pagetitle,
    'description' => $description,
    'url' => $url,
    'image' => $image
  ));
}

$output = $pdoTools->getChunk('@FILE chunks/tpl.newsletter.wrapper.tpl',array(
  'output' => $output
));

echo $output;

exit();
Открываем его браузере и проверяем.
Роман
Роман
Вывел, но дальше что то не пошло joxi.ru/D2PJvY5Tq93wBr

Что делаю не так?
Александр Мальцев
Александр Мальцев
Проверьте может что-то опустили или сделали не так.
Попробуйте просто вывести значения на экран:
foreach ($resources as $resource) {
  print_r($resource->toArray());
}
Роман
Роман
Вывелось: joxi.ru/V2V4jLZHdQwyEr

Чанки:
tpl.newsletter.article.tpl
tpl.newsletter.wrapper.tpl

На месте, и заполнены

Весь мой код этой страницы:
<?php

require_once 'config.core.php';
require_once MODX_CORE_PATH.'model/modx/modx.class.php';
$modx = new modX();
$modx->initialize('web');
$modx->getService('error','error.modError', '', '');

$pdoTools = $modx->getService('pdoTools');

$output = '';

$parent = array(19);
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => $parent
));
$query->limit(5);
$resources = $modx->getCollection('modResource', $query);

$count = count($resources);

if ($count == 0) {
  exit();
}

foreach ($resources as $resource) {
  $id = $resource->get('id');
  $pagetitle = $resource->get('pagetitle');
  $description = $resource->get('description');
  $url = $modx->makeUrl($id,'','','https');
  $image = $modx->getObject('modTemplateVarResource',array( 'tmplvarid' => 2, 'contentid' => $id ));  
  if (is_object($image)) {
    $image = 'http://mysite.ru/assets/images/'.$image->get('value');
  } else {
    $image = '';
  }
  $output .= $pdoTools->getChunk('@FILE chunks/tpl.newsletter.article.tpl',array(
    'pagetitle' => $pagetitle,
    'description' => $description,
    'url' => $url,
    'image' => $image
  ));
}



$output = $pdoTools->getChunk('@FILE chunks/tpl.newsletter.wrapper.tpl',array(
  'output' => $output
));

echo $output;

foreach ($resources as $resource) {
  print_r($resource->toArray());
}

exit();
Александр Мальцев
Александр Мальцев
В этом примере чанки должны быть расположены по пути «core/elements/chunks/».
В чанке «tpl.newsletter.wrapper.tpl» плейсхолдер [[+newsletter.description]] необходимо заменить на {$output}, т.к. он используется в коде.
Роман
Роман
Чанки там и лежали. Запустилось пошло.

Теперь осталось понять, почему мои TV не выводятся
Александр Мальцев
Александр Мальцев
Выведи значение:
if (is_object($image)) {
  echo 'TV value:' . $image->get('value');
} else {
  echo 'TV value:';
}
Роман
Роман
Разобрался. Спасибо
kovasal
kovasal
Добрый день, Александр!
У меня в форме обратной связи на сайте чекбокс «подписаться на новости».
Решил сделать хук для Formit.
Проверку на подписанность юзера в таблице sendex'а сделать вроде соображу как.
А как из этого сниппета запустить sendex, чтобы он отработал так же, как при нажатии кнопки «подписаться» подскажите?
Александр Мальцев
Александр Мальцев
Добрый день!
В этом случае вам необходимо самостоятельно организовать логику, используя методы Sendex.
Например:
<?php
/** @var array $scriptProperties */
/** @var Sendex $Sendex */
$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 '';

$email = $hook->getValue('email'); // получаем значение email
$id = '0'; // id пользователя (по умолчанию)
$linkTTL = 1800; // время жизни ссылки
$tplActivate = 'tpl.Sendex.activate'; // чанк, содержащий email шаблон
$output = '';
$result = false;

// авторизирован ли пользователь (true - авторизован, false - нет)
$isAuthenticated = $modx->user->isAuthenticated($modx->context->key);
if ($isAuthenticated) {
    $id = $modx->user->id; // получаем id пользователя
}
$newsletter = $modx->getObject('sxNewsletter', 1); // sxNewsletter (1 - id подписки)
// отправка проверочного кода на email анонимного юзера
$response = $newsletter->checkEmail($email, $id, $linkTTL);
if ($response === true) {
    // пользователь уже подписан
    $output = 'Пользователь уже подписан';
} elseif ($response === false) {
    // если email пустой или он является не корректным
    $output = 'Указан не корректный 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) {
        // ошибка при отправке email
        $output = 'Ошибка при отправке email';
    } else {
        // email отправлен
        $output = 'Email отправлен. Перейдите по ссылке из письма!';
        $result = true;
    }	
}
$hook->setValue('rsubscribe', $output);
return $result;
kovasal
kovasal
Спасибо. А я так понимаю нужно еще поле name=«rsubscribe» создать, чтобы туда прописывались сообщения?
Александр Мальцев
Александр Мальцев
Не знаю, всё зависит от вашей формы. Можете просто создать плейсхолдер для вывода сообщений без поля rsubscribe.
kovasal
kovasal
Большую работу проделываете, Александр, помогая и подсказывая начинающим. И статьи очень интересные и понятные. Вы педагог от бога!
Владимир
Владимир
Здравствуйте, подскажите пожалуйста куда надо вставить — Пример чанка, который будет использовать для оформления каждой статьи в письме? Или как назвать чанк?
Александр Мальцев
Александр Мальцев
Здравствуйте! Добавил данную информацию в статью.
Владимир
Владимир
Огромное спасибо! Разобрался.
Александр
Александр
Александр, отличное руководство! Скажите в чём может быть проблема, создаю статью в ручную и в админке sendex рассылаю вручную письма с рассылкой для проверки, письма приходят только с пустым шаблоном, где копать?

И непонятно как прописать время рассылки в файле: create.letters.php?
Александр Мальцев
Александр Мальцев
Спасибо!
Выборка ресурсов осуществляется с помощью следующего кода:
$parent = array(5,6,7);
$query = $modx->newQuery('modResource', array(
  'publishedon:>=' => strtotime('-7 days'),
  'parent:IN' => $parent
));
$query->limit(5);
$resources = $modx->getCollection('modResource', $query);
Проверьте, опубликованы ли созданные ресурсы. А также корректно ли вы выставили значение переменной $parent.

Время рассылки настраивается с помощью cron, а не в файле. Файл create.letters.php не может сам себя запустить. Его запуск осуществляет планировщик cron.
sergey
sergey
modstore.com/ это верный сайт с Sendex?
Александр Мальцев
Александр Мальцев
Исправил. Правильный поставщик конечно же modstore.pro.
Arhivar
Arhivar
А как сделать чтобы Sendex все сообщения брал из папки en lexicon/en/default.inc.php.
($_lang['sendex_menu_desc'] = 'Newsletters management'; — так нужно)
То есть, как его на английский перевести, чтоб все предупреждения типа «введите emal», на английском были.
Arhivar
Arhivar
И еще вопрос: Вставил подписку в модальное окно, из этой статьи -https://itchief.ru/lessons/bootstrap-3/bootstrap-3-modal-window

Но при нажатии на кнопку, подписать, закрывается модальное окно! Как сделать чтоб окно не закрывалось, при нажатии на кнопку отправить?

Сделал так:
[[!AjaxForm?
&form=`tplSendexSubscribeGuest`
&snippet=`Sendex`
&id=`1`
]]
Ничего не работает!
Александр Мальцев
Александр Мальцев
Обычно это задаётся посредством настроек контекстов.
Например, у вас есть контекст сайта на английском языке. В настройки это контекста вы добавляете параметр cultureKey со значением en.После этого вся информация у вас на сайте будет отображаться на английском языке.
Александр Мальцев
Александр Мальцев
AjaxForm заточен под FormIt и так просто это не получится осуществить.
Arhivar
Arhivar
Спасибо! помогло. С контекстами заодно познакомился..) До этого не приходилось сталкиваться!
Анатолий
Анатолий
Александр, очень хороший сайт у вас. Спасибо.

Вопросы чуть поподробнее.
1.Куда вставить этот чанк??
Пример чанка, который будет использовать для оформления каждой статьи в письме:
2. Как создать эту задачу??
Пример создания новой задачи для cron с помощью панели управления виртуальным хостингом
Спасибо за сайт.
Александр Мальцев
Александр Мальцев
Спасибо.
1. Данный чанк должен иметь имя tpl.newsletter.article.
2. Это зависит от хостера. Необходимо в его справке найти соответствующий раздел и посмотреть, как это делается. Вот пример справки от Beget: _https://beget.com/ru/manual/crontab
Arhivar
Arhivar
Прямо, ждал эту статью!!! )
Александр Мальцев
Александр Мальцев
Рад, что статья понравилась.
nika
nika
Хорошая статья, все понятно написано, спасибо за труд.
Хотела реализовать на практике не ному справиться с приложением sendex.
Помогите пожалуйста разобраться!
На вкладке Пакеты Sendex не активный, при переходе в приложение ничего не происходит
itchief.ru/assets/uploadify/2/a/4/2a4ba9bd8c6f1b388e70f2d792f1a9a7.jpg
Александр Мальцев
Александр Мальцев
Пожалуйста! На третьей ветке MODX много дополнений не работает. Здесь только использовать MODX 2.8.4 или любую другую версию из второй ветки.