Блог без комментариев — это монолог. Чтобы превратить его в сообщество, нам нужна система обсуждений. В этом уроке мы интегрируем комментарии в наш шаблон Porto, сохранив его дизайн, но заставив всё работать динамически.
Мы рассмотрим два пути: профессиональный (компонент EasyComm) и альтернативный (бесплатные JS-виджеты).
Вариант 1: EasyComm (рекомендуемый)
Почему это лучший выбор? Комментарии хранятся в вашей базе данных. Это означает, что поисковики (Google/Yandex) видят этот текст и индексируют его, что отлично для SEO. Плюс, вы полностью контролируете дизайн и отсутствие чужой рекламы.
1. Подготовка
Зарегистрируйтесь / авторизуйтесь на сайте modstore.pro. После этого перейдите на страницу дополнения easyComm, добавьте его в корзину, оформите заказ.

При выборе сайта, если не видите своего домена просто выберите новый сайт. Да при оплате по СБП возможны задержки, вы можете увидеть примерно вот такое сообщение:
Похоже, оплата ещё не прошла. Иногда платёжная система задерживает ответ. Подождите несколько минут — статус должен обновиться. Если деньги списались, но статус так и не обновился, напишите на info@modstore.pro

Статус у меня обновился примерно через 15 минут. Далее чтобы нам установить купленное дополнение нужно:
- Перейти в свой профиль на страницу с ключами в modstore.pro, для этого щелкаем по Кнопке со своим именем (или email) и в выпадающем меню выбираем «Ключи для сайтов». На открывшейся странице копируем ключ.

- Далее идем в админку сайта Пакеты — Установщик. На открывшейся странице переходим во вкладку Поставщики. Далее щелкаем правой кнопкой мыши по поставщику Modstore и выбираем редактировать. В модальном окне прописываем email (с которого покупали ключ), вставляем ранее скопированный ключ и сохраняем.

- Устанавливаем пакет.
- Перейдите в системные настройки компонента:

И произведите основные системные настройки (опционально).

2. Создаем чанки
Мы разобьем верстку Porto на две логические части. Создайте файлы в папке core/elements/chunks/blog/comments/.
А. Комментарии (ec_messages.tpl)
Здесь мы соединяем верстку Porto с данными easyComm. Обратите внимание на кнопку «Reply» — атрибуты data-ec-* критически важны для работы ответов.
{if $messages?}
<ul class="comments">
{foreach $messages as $message}
<li id="ec-message-{$message.id}">
<div class="comment">
<div class="img-thumbnail img-thumbnail-no-borders d-none d-sm-block">
<img class="avatar rounded-circle"
src="{$message.avatar ?: '/assets/img/avatar-default.png'}"
alt="{$message.user_name}">
</div>
<div class="comment-block">
<div class="comment-arrow"></div>
<span class="comment-by">
<strong class="text-dark">{$message.user_name}</strong>
{if $message.replies_enable?}
<span class="float-end">
<a href="javascript:void(0)"
class="js-ec-reply"
data-ec-thread="{$message.thread_name}"
data-ec-message="{$message.id}">
<i class="fas fa-reply"></i> {'ec_fe_reply' | lexicon}
</a>
</span>
{/if}
</span>
<p>{$message.text}</p>
<span class="date float-end">
{$message.created_on | date_format : "%d %B %Y at %H:%M"}
</span>
</div>
</div>
{if $message.replies?}
<ul class="comments reply">
{foreach $message.replies as $reply}
<li id="ec-reply-{$reply.id}">
<div class="comment">
<div class="img-thumbnail img-thumbnail-no-borders d-none d-sm-block">
<img class="avatar rounded-circle"
src="{$reply.avatar ?: '/assets/img/avatar-default.png'}"
alt="{$reply.user_name}">
</div>
<div class="comment-block">
<div class="comment-arrow"></div>
<span class="comment-by">
<strong class="text-dark">{$reply.user_name}</strong>
{if $message.replies_enable?}
<span class="float-end">
<a href="javascript:void(0)"
class="js-ec-reply"
data-ec-thread="{$message.thread_name}"
data-ec-message="{$message.id}"
data-ec-parent="{$reply.id}">
<i class="fas fa-reply"></i> {'ec_fe_reply' | lexicon}
</a>
</span>
{/if}
</span>
<p>{$reply.text}</p>
<span class="date float-end">
{$reply.created_on | date:'%d %B %Y %H:%M'}
</span>
</div>
</div>
</li>
{/foreach}
</ul>
{/if}
</li>
{/foreach}
</ul>
{/if}
Б. Форма добавления (ec_form.tpl)
Адаптируем форму Porto под поля easyComm.
<h3 class="text-color-secondary text-capitalize font-weight-bold text-5 m-0 mb-3 mt-5">
{'ec_fe_message_add' | lexicon}
</h3>
<form class="custom-form-simple-validation p-4 rounded bg-color-grey ec-form" method="post" role="form" id="{$fid}" action="" data-ec-thread="{$thread}">
{* --- ОБЯЗАТЕЛЬНОЕ СКРЫТОЕ ПОЛЕ --- *}
<input type="hidden" name="thread" value="{$thread}">
{* --- АНТИСПАМ (Критически важно!) --- *}
{* Этот блок скрывается через CSS easyComm. Если робот его заполнит — форма не отправится *}
<div class="ec-form__row ec-antispam">
<label for="{$fid}-{$antispam_field}" class="control-label">{'ec_fe_message_antismap' | lexicon}</label>
<input type="text" name="{$antispam_field}" class="form-control" id="{$fid}-{$antispam_field}" value="" />
</div>
<div class="p-2">
<div class="row">
{* ИМЯ *}
<div class="form-group col-lg-6">
<label class="form-label required mb-1 font-weight-bold text-dark" for="{$fid}-user_name">
{'ec_fe_message_user_name' | lexicon}
</label>
<input type="text" name="user_name" class="form-control py-3 px-3 border-0 box-shadow-none"
id="{$fid}-user_name" value="{$user_name}" required>
{* Блок ошибки обязательно с ID: {$fid}-имяполя-error *}
<span class="ec-error help-block text-danger mt-1" id="{$fid}-user_name-error"></span>
</div>
{* EMAIL *}
<div class="form-group col-lg-6">
<label class="form-label required mb-1 font-weight-bold text-dark" for="{$fid}-user_email">
{'ec_fe_message_user_email' | lexicon}
</label>
<input type="email" name="user_email" class="form-control py-3 px-3 border-0 box-shadow-none"
id="{$fid}-user_email" value="{$user_email}" required>
<span class="ec-error help-block text-danger mt-1" id="{$fid}-user_email-error"></span>
</div>
</div>
{* ТЕКСТ КОММЕНТАРИЯ *}
<div class="row">
<div class="form-group col">
<label class="form-label required mb-1 font-weight-bold text-dark" for="{$fid}-text">
{'ec_fe_message_text' | lexicon}
</label>
<textarea name="text" rows="8" class="form-control p-3 border-0 box-shadow-none"
id="{$fid}-text" required>{$text}</textarea>
<span class="ec-error help-block text-danger mt-1" id="{$fid}-text-error"></span>
</div>
</div>
{* КАПЧА (ReCaptcha) *}
{$recaptcha}
{if $agreementCheckbox}
<div class="ec-form__row checkbox ec-input-parent">
<label>
<input type="checkbox" name="agree" value="1"> {'ec_fe_agree' | lexicon}
</label>
</div>
{/if}
<div class="row">
<div class="form-group col mb-0">
<input type="submit" name="send" value="{'ec_fe_send' | lexicon}"
class="btn btn-primary btn-modern" data-loading-text="Loading...">
</div>
</div>
</div>
</form>
{* Блок успешной отправки (ОБЯЗАТЕЛЬНО ВНЕ ФОРМЫ или РЯДОМ) *}
<div id="{$fid}-success"></div>
3. Сборка (post_comments.tpl)
Теперь собираем всё вместе в файле core/elements/chunks/blog/post_comments.tpl. Этот файл мы подключаем в шаблон статьи.
<div id="comments" class="post-block post-comments">
{* Определяем ID ветки *}
{var $thread = 'post-' ~ $_modx->resource.id}
{* 1. Получаем количество комментариев заранее *}
{var $count = '!ecThreadRating' | snippet : ['thread' => $thread, 'tpl' => '@INLINE {$count}']}
{* 2. Если комментарии есть — выводим заголовок и список *}
{if $count > 0}
<h3 class="text-color-secondary text-capitalize font-weight-bold text-5 m-0 mb-3">
{$count} comments for "{$_modx->resource.pagetitle}"
</h3>
{* Вызываем сниппет ecMessages, вся логика внутри tpl *}
{'!ecMessages' | snippet : [
'thread' => $thread,
'tpl' => '@FILE chunks/blog/comments/ec_messages.tpl',
]}
{/if}
{* 3. Форма добавления (всегда видна) *}
{'!ecForm' | snippet : [
'thread' => $thread,
'tplForm' => '@FILE chunks/blog/comments/ec_form.tpl'
]}
</div>
Вариант 2: Бесплатные альтернативы
Если бюджет ограничен или не хочется настраивать компонент, можно воспользоваться внешними сервисами. Они подключаются через JS-код.
1. Giscus (Для IT-блогов)
Идеально для технарей. Комментарии хранятся в GitHub Discussions вашего репозитория. Бесплатно, без рекламы, open-source.
- Требует публичный репозиторий на GitHub.
- Пользователи должны иметь аккаунт GitHub для входа.
Подключение: сгенерируйте код на сайте giscus.app и вставьте его в чанк:
<div class="giscus post-block post-comments mt-5"></div>
<script src="https://giscus.app/client.js"
data-repo="ВАШ_ПОЛЬЗОВАТЕЛЬ/ВАШ_РЕПОЗИТОРИЙ"
data-repo-id="ID_РЕПОЗИТОРИЯ"
data-category="Announcements"
data-category-id="ID_КАТЕГОРИИ"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="light"
data-lang="ru"
crossorigin="anonymous"
async>
</script>
2. Comments.app (Telegram)
Виджет от разработчиков Telegram. Очень удобно для рунета.
- Комментарии привязываются к каналу Telegram.
- Авторизация в один клик через «Телегу».
<div class="post-block post-comments mt-5">
<script async src="https://comments.app/js/widget.js?3"
data-comments-app-website="ВАШ_ID_С_САЙТА"
data-limit="5"
data-color="E22F38"
data-dislikes="1"
data-outlined="1">
</script>
</div>
3. Disqus (Классика)
Самый известный сервис. Легко ставится, но в бесплатной версии показывает много рекламы и тяжелые трекеры, что замедляет сайт.
Итог
Если вы строите серьезный сайт на базе Porto и MODX — инвестиция в easyComm окупится за счет SEO и целостного дизайна. Если же вы делаете блог для разработчиков — смело ставьте Giscus.











