Modx Evo комменты к товарам на Jot (вопросы и отзывы)

Jot - сниппет для создания и управления комментариями в CMS modx Evolution. До этого был опыт подключения комментов, но на Revo. Несколько раз приходилось править чужие скрипты и на Jot. И вот, наконец, заказали подключить коменты к интернет-магазину. В качестве вопросов по товару и как отзывы о товаре. И как показал опыт с другими сниппетами, если всю работу не зафиксить в блоге - через месяц все забудется. Нет задачи пошагово все описать. Только знаковые моменты. Чтоб легче было потом освежить в памяти. В инете полно подробных пошаговых инструкций. Пишу, как всегда, больше для себя. Но мало ли еще кому сгодится.

Насторожило то, что у заказчика уже стоял сниппет Jot. Это навело на мысль, что уже кто-то пытался его установить. Запустил на тестовой карточке товара:

 [[Jot?
 &subscribe=`1` 
 &pagination=`10`
 ]]
    
Так и есть. Поймал ошибку SQL.

Лечение: исправил файл "/assets/snippets/jot/includes/jot.install.db.sql" - в конце генерации таблиц сделал так:

...) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
    
Запустил и все заработало. Создались таблицы. Правда не появилась админка. Но пока пусть.

Вроде все ОК. Но не покидали смутные предчувствия. Так пробежавшись по исходникам - не нашел я запуска через конфигурации. Все боле-менее новые сниппеты сейчас предусматривают запуск через конфиг. Это очень удобно для любителей PHP. Все можно настроить в одном файле и не скакать по десятку чанков и сниппетов. Причем припомнил - вроде у кого-то настраивал jot именно с конфигом.

Полазив минут 10 по инету нашел jotX тут https://github.com/Temus/JotX. Улучшенный jot. Как раз то, что мне надо. Заменил все на файлы jotx. Теперь все ОК! Можно делать дальше) И больше уже не комплексуя))).

Я как то настороженно отношусь к отечественным разработкам. Особенно после DocListera. Но тут нет выхода. Недостаток "наших" разработчиков - это отсутствие нормальной документации. Надо сказать, что опасения оправдались... . Пришлось несколько дней потратить на изучение исходников, чтоб увереннее себя чувствовать. Иначе ощущаешь себя реальным дебилом. Вот несколько фраз из доков:

  Новые параметры.
  ..................
  
  docids - список docid, можно указывать диапазоны
  tagids - список tagid, через запятую
  userids - список id пользователей, через запятую. Для веб-пользователей - отрицательные.
  ..................     
  Параметры docids и tagids используются для вывода данных,
  docid и tagid - для ввода текущих, поэтому они разделены
  ..................     
Какого ввода? Какого вывода? Догадываюсь, что ввод - форма нового коммента, а вывод - вывод комментов на странице.
 
  ..................     
 События.
 В каждом из двух классов свои. 
  ..................     
Какие 2 класса? Может я один не понимаю? Раз десять перечитал все, так и не понял. А в принципе - написали ребята довольно много, в целом все работаем. Спасибо и на этом).

Есть три варианта подключения

  • Вопрос-Ответ
  • Древовидные комментарии
  • Древовидные комментарии с аякс
  • Как всегда, выбираем самый геморойный- Древовидные комментарии с аякс!
[!JotX? &config=`tree-ajax`!]
    

Ajax тут реализован несколько неожиданно. Для меня. В качестве ajax-хендлера выступает сама наша страница(ресурс). Т.е. в итоге тот же наш jot. Естественно, с теми же параметрами. В принципе, логично. Принцип работы - сниппет, определив, что прилетел ajax-запрос обрабатывает его и делает die($output). Т.е. прерывает работу парсера и возвращает в броузер то, что сам сформировал. Эффективнее бы использовать коннектор, чтоб не грузить парсер лишней работой. Ну да ладно. Со стороны всегда виднее.

Создадим свой конфиг, просто для начала скопировав стандартный. Т.е. скопируем "/assets/snippets/jot/configs/tree-ajax.config.php" в "/assets/snippets/jot/configs/cppv-tree-ajax.config.php"

[!JotX? &config=`cppv-tree-ajax`!]
    

Конфигурация - это PHP-файл. Где параметры задаются как переменные. Тут же можно назначить все функции-обработчики и шаблоны вывода.

В JotX режимы (в jot - action), вынесены в файлы. Все режимы в "/assets/snippets/jot/actions". Вообще это уже тенденция. Ранее старались писать расширения под дизайнеров и менеджеров. От этого число параметров катастрофически росло. Но это тупиковый путь. Сейчас тупо пишутся с учетом того, что внедрять будут программеры. От этого все только выиграли. Решения стали очень гибкими, настраивать стало проще. Кроме дизайнеров. Пусть себе рисуют).

Еще одним забавный момент - как реакцию на события можно назначить плагины:

    [!JotX? &onBeforeValidateFormField=`nolink,onlyrus` !]
Можно в качестве плагина назначить сниппет, но можно и файл PHP. Файл (напр. "nolink.inc.php") будет искаться тут: "/assets/snippets/jot/plugins/". Это очень круто. И удобно.

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

Куда ж без глюков, особенно если учесть происхождение))).

Нестабильно работает отправка уведомлений. На Яндекс-почту - нормально, а на mail.ru - нет. Я с таким уж сталкивался. Выход - использовать SMNTP в phpMailer. К сожалению, в jotX обработка почты встроенная и никак туда не влезть. Допустим в FormIt можно отключить отправку и в хуках отправить как сам хочешь. В принципе и тут можно отключить уведомления. Но тогда не будут и обрабатываться шаблоны для рассылок. Придется влезать в исходник.

Еще момент. На домашнем компе модерация(удаление, редактирование всех комментов) подключается даже при просмотре страниц. Если на других закладках вошел в админку. Что очень удобно. Не надо лезть в JoСo. И при ответах нужно заполнить только комментарий, почта и имя само заполняется из настроек логина.

А на рабочем - нет. Хоть и сижу в админке, в комментах приходится заполнить и имя и емайл.

В данной ситуации нет иного пути как лезть в исходники.

Запуск jot

  • $Jot = new CJot;
    • $this->provider = new CJotDataDb; - подключение к базе (/assets/snippets/jot/includes/jot.db.class.inc.php)
  • загрузка параметров $Jot->Set("path",$jotPath); и т.д.
  • загрузка событий $Jot->Set("onBeforeConfiguration", $onBeforeConfiguration); и т.д.
  • return $Jot->Run();
    • $this->doEvent("onBeforeConfiguration");
    • $this->provider->events... - назначение событий базы
    • $this->config["snippet"]["input"] = $this->parameters;
    • загрузка в конфиг параметров и назначение дефолтов. типа: $this->config["docid"] = !is_null($this->Get("docid")) ? intval($this->Get("docid")):$modx->documentIdentifier;
    • вычисляется ID экземпляра по docId и tagId - $this->config["id"]
    • установка прав - $this->config["permissions"]["post"] и т.д
    • установка модерации - $this->config["moderation"]["type"]
    • права доступа(булевы) - $this->isModerator, $this->isTrusted, $this->canPost, $this->canView, $this->canEdit
    • назначение шаблонов - $this->templates["form"] ...
    • параметры запроса. ключи и значения - $this->config["querykey"]["action"] и $this->config["query"]["action"] ...
    • признак обработки запроса о формы - $this->isPostback
    • валидация $this->config["validate"] в массив $this->config["form"]["validation"]
    • $this->doEvent("onConfiguration");
    • загрузка полей формы - $this->form["source"] = $this->config["query"]["id"]; ...
    • режим - $this->config["mode"]["type"] = "comments"; ....
    • генерация ссылок $this->config["link"]["id"] = $this->_idshort;
    • Проверка на первый запуск - $this->provider->FirstRun($this->config["path"]);
    • Badwords
    • Модерация - $this->config["moderation"]["view"] = $view = isset($_GET[$this->config["querykey"]["view"]]) ? $this->config["query"]["view"]: 2;
    • определение статуса подписки - $this->config["subscription"]["status"] = 1
    • $commentId = $this->config["query"]["id"];
    • $this->doEvent("onBeforeRunActions");
    • Active action - switch ($this->config["mode"]["active"]) { case "delete": $this->doModerate('delete',$commentId); break; ...
    • $this->doEvent("onRunActions");
    • Самое главное(форма, рассылка и прочее) - Form Processing $frmCommentId = ($this->form["edit"]) ? $commentId : 0; если с комментом все ОК - if ($id && $pObj->isValidComment($this->config["docids"],$this->config["tagids"],$id) && $this->canEdit) $this->processForm($frmCommentId);
      • $formMode = $this->config["mode"]["passive"]; $saveComment = 1;
      • $this->form["action"] = $this->config["link"]["current"];
      • $pObj->Comment($id);($pObj=$this->provider;) считывание коммента из базы по ID
        		            
        	function Comment($id=0){
        		global $modx;
        		$this->isNew = $id == 0;
        		if(!$this->isNew){
        			
        			// Standard Fields
        			$tbl = $this->tbl["content"];
        			$rs = $modx->db->query("select * from $tbl where id = $id");
        			$this->fields = $modx->db->getRow($rs);
        			$this->fields['id'] = $id;		
        			
        			// Custom Fields
        			$cust = $this->getCustomFieldsArray($id);
        			$this->cfields = $cust[$id];
        			if (!is_array($this->cfields)) $this->cfields = array();
        		}
        		else {		
        			$this->fields = array(
        				'title' => 'new comment',
        				'tagid' => '',
        				'published' => 1,
        				'uparent' => 0,
        				'parent' => 0,
        				'flags' => '',
        				'secip' => '',
        				'sechash' => '',
        				'content' => '',
        				'mode' => 0,
        				'createdby' => 0,
        				'createdon' => 0,
        				'editedby' => 0,
        				'editedon' => 0,
        				'deleted' => 0,
        				'deletedon' => 0,
        				'deletedby' => 0,
        				'publishedon' => 0,
        				'publishedby' => 0
        		    );
        		}
        		//onGetCommentFields event
        		$this->doEvent("onGetCommentFields",array("id"=>$id));
        	}
        		            
        		            
        		                   
      • Если с комментом что-то не так - $pObj->Comment(0); // fix for update/new problem
      • Если автор или модератор, то есть кнопки $this->form['edit'] и $this->form['save'] - if (($pObj->Get("createdby") == $this->config["user"]["id"]) || $this->isModerator). Иначе $saveComment = 0; ти кнопок не будет
      • // If this is not a postback or a false edit then return. if (!$this->isPostback || !$saveComment) return;
      • // If we get here switch passive mode back and let the save option decide the final passive mode $this->config["mode"]["passive"] = $formMode;
      • //onBeforePOSTProcess event if (null !== ($output = $this->doEvent("onBeforePOSTProcess",array("id"=>$id,"pObj"=>&$pObj,"saveComment"=>&$saveComment)))) return;
      • // For every field posted loop foreach($_POST as $n=>$v) { - запись поллученных полей в базу $pObj->Set("title",$v); проверка на матюги; проверка двойной отправки через хэш($_SESSION['JotLastPost'] = $chkPost;), (Post Delay?), капча, валидация
      • установка полей базы.....$pObj->Set("published",$this->form['published']);..... if ($saveComment) $pObj->Save();
      • Запуск оповещений

        // Notify Subscribers
        if ($saveComment && $this->form['published']>0 && $this->config["subscription"]["enabled"]) $this->doNotify($pObj->Get("id"),"notify");

        // Notify Moderators
        if ($saveComment && (($this->form['published']==0 && $this->config["moderation"]["notify"]==1) || ($this->form['published'] >0 && $this->config["moderation"]["notify"]==2))) $this->doNotify($pObj->Get("id"),"notifymoderator");

        // Notify Author
        if ($saveComment && $this->config["moderation"]["notifyAuthor"]) $this->doNotify($pObj->Get("id"),"notifyauthor");

        // Notify Emails
        if ($saveComment && !empty($this->config["notifyEmails"])) $this->doNotify($pObj->Get("id"),"notifyemails");

            
        
        	// Notifications
        	function doNotify($commentid=0,$action="notify") {
        		global $modx;
        		
        		// Get comment fields
        		$cObj = $this->provider;
        		$cObj->Comment($commentid);
        		$comment = $cObj->getFields();
        		unset($cObj);
        		
        		switch ($action) {
        			case "notify":
        				$user_ids = $this->provider->getSubscriptions($this->config["docid"],$this->config["tagid"]);
        				$subject = $this->config["subject"]["subscribe"];
        				break;
        			case "notifymoderator":
        				$user_ids = $this->getMembersOfWebGroup($this->config["permissions"]["moderate"]);
        				$subject = $this->config["subject"]["moderate"];
        				break;
        			case "notifyauthor":
        				$user_ids = array($this->config["authorid"]);
        				$subject = $this->config["subject"]["author"];
        				break;
        			case "notifyemails":
        				$user_ids = $this->config["notifyEmails"];
        				$subject = $this->config["subject"]["emails"];
        				break;
        		}
        
        		include_once MODX_MANAGER_PATH . "includes/controls/class.phpmailer.php";
        		foreach ($user_ids as $user_id){
        			if ($this->config["user"]["id"] !== $user_id) {
        				if ($action == "notifyemails") {
        					$user = array();
        					$user["email"] = $user_id;
        					$user["username"] = $this->config["notifyNames"][$user_id];
        				} else {
        					$user = $this->getUserInfo($user_id);
        				}
        
        				$tpl = new CChunkie($this->templates[$action]);
        				$tpl->AddVar("siteurl","http://".$_SERVER["SERVER_NAME"]);
        				
        				//onBeforeNotify event
        				if (null === $this->doEvent("onBeforeNotify",array("commentid"=>$commentid,"action"=>$action,"tpl"=>&$tpl,"subject"=>&$subject,"comment"=>&$comment,"user"=>&$user))) {
        					$tpl->AddVar("jot",$this->config);
        					$tpl->AddVar("comment",$comment);
        					$tpl->AddVar("recipient",$user);
        					$mail = new PHPMailer();
        					//add smtp method by Dmi3yy
        					if ($modx->config['email_method'] == 'smtp') {
        						$mail->IsSMTP(); // отсылать используя SMTP
        						$mail->Host	 = $modx->config['email_host']; // SMTP сервер
        						$mail->SMTPAuth = true;	 // включить SMTP аутентификацию
        						$mail->Username = $modx->config['email_smtp_sender']; // SMTP username
        						$mail->Password = $modx->config['email_pass']; // SMTP password
        						
        						$mail->From		= $modx->config['email_smtp_sender'];
        						$mail->Port     = $modx->config['email_port'];
        					}else{
        						$mail->IsMail();
        						$mail->From     = $modx->config["emailsender"];
        					}
        					$mail->CharSet = $modx->config["modx_charset"]; 
        					$mail->IsHTML(false);
        					$mail->FromName = $modx->config["site_name"];
        					$mail->Subject = $subject;
        					$mail->Body = $tpl->Render();
        					$mail->AddAddress($user["email"]);                 
        					$res_=$mail->Send();           
        				}
        			}
        		}
        	}
        
        
        
        
        
        
            	                    
      • //onProcessForm event
        if (null !== ($output = $this->doEvent("onProcessForm",array("id"=>$id,"pObj"=>&$pObj,"saveComment"=>$saveComment))))
        return;
    • $this->doEvent("onBeforeProcessPassiveActions");
    • сами комменты и прочее (Passive Action) -
      $actionPath = $this->config["path"].'actions/' . $this->config["mode"]["passive"] . '.inc.php';
      $object = & $this;
      if(is_file($actionPath)) {
       include_once $actionPath;
       $modeName = $this->config["mode"]["passive"] . '_mode';
       if(function_exists($modeName)) $this->output = $modeName($object);
      }
    • $this->doEvent("onProcessPassiveActions");
    • output debug
    • плейсхолдеры - if ($this->config["placeholders"]) $this->setPlaceholders($this->config,"jot");
    • загрузка CSS - if ($this->config["css"]["include"]) $modx->regClientCSS(MODX_BASE_URL.$this->config["css"]["file"]);
    • загрузка JS - if ($this->config["js"]["include"]) $modx->regClientStartupScript(MODX_BASE_URL.$this->config["js"]["file"]);
    • $this->doEvent("onReturnOutput");
    • return $this->output;

Модерация "LIVE"

Чтоб удалять, редактировать прямо на месте вывода - $chSession==1 или $memOfmoderate==1. Т.е. или вход в админке, или член группы модераторов. $chSession почему-то не всегда срабатывает.

Перехват отправки почты

Это лучше сделать через событие onBeforeNotify. Надо учитывать, что место вызова этого события не совсем удачно в исходнике. Почемуто уже после подключения "/manager/includes/controls/class.phpmailer.php". Я ж планирую подключить свой, модифицированный мэйлер.

    $this->doEvent("
        onBeforeNotify",
        array(
            "commentid"=>$commentid,
            "action"=>$action,
            "tpl"=>&$tpl,
            "subject"=>&$subject,
            "comment"=>&$comment,
            "user"=>&$user
            )
        )
    
    
Чтобы после события почта больше не обрабатывалась - надо что-нибудт вернуть. Лучше "true".

Обработчик событий реализован отлично! Допустим: устанавливаем событие onBeforeNotify='subscribe' Можно через запятую несколько указать.
jotX ищет файл "/assets/snippets/jot/plugins/subscribe.inc.php". Подключает его.
И в нем запускается function subscribe(&$object,$params)
а в ней case:$object->event="onBeforeNotify". Например в нашем случае(по-умолчанию):

case "onBeforeNotify":
* не отправлять свой комментарий */
$hash = isset($params["user"]["hash"]) ? $params["user"]["hash"] : '';
if (isset($_COOKIE['jot-hash']) && $_COOKIE['jot-hash'] == $hash) return true;
/* добавить хэш в шаблон */
if ($hash) $params["tpl"]->template = str_replace('[+jot.link.unsubscribe+]','[+jot.link.unsubscribe+]&hash='.$hash,$params["tpl"]->template);
elseif (!$object->config["subscribe"] && $params["action"]=="notify") return true;
break;

Учитывая все вышеизложенное в конфиге заменяем $onBeforeNotify: $onBeforeNotify =cppvNotify;
Создаем файл "/assets/snippets/jot/plugins/cppvNotify.inc.php"

db->config["table_prefix"]."jot_subscriptions_guest";
	                   add_test_str('$object->event='.$object->event);     
	switch($object->event) {
		case "onBeforeNotify":
			/* не отправлять свой комментарий */
			$hash = isset($params["user"]["hash"]) ? $params["user"]["hash"] : '';
			if (isset($_COOKIE['jot-hash']) && $_COOKIE['jot-hash'] == $hash) return true;
			/* добавить хэш в шаблон */
			if ($hash) $params["tpl"]->template = str_replace('[+jot.link.unsubscribe+]','[+jot.link.unsubscribe+]&hash='.$hash,$params["tpl"]->template);
			elseif (!$object->config["subscribe"] && $params["action"]=="notify") return true;
			....................................................
						тут свой код. я подключил последнюю версию майлера.
			....................................................
			return true;
			break;
	}
}
?>
Я подключил mailer в режиме SMNTP. Долго не мог понять, почему не работает. Оказалось, что мешается майлер подгруженный jotX до вызова нашего события. Пришлось тупо закомментировать вызов. После этого все заработало. Все-таки пришлось подправить исходник.

Переменные доступные в обработчике и полезные для отправки на емайл.

$params['user']=Array
(
    [email] => anna1999@mail.ru
    [username] => подписчик
)
$params['subject']=Новый комментарий
$params['action']=notifyemails
$params['commentid']=76
$params['tpl'] = CChunkie Object
$params['tpl']['template']= сырой TPL Уважаемый(ая) [+recipient.username+],.....
            Имя: [+comment.custom.name+]
            Email: [+comment.custom.email+] Тема: [+comment.title+]
            Сообщение:[+comment.content+] Отписаться от уведомлений: [+siteurl+][+jot.link.unsubscribe+]
$params['comment'] = Array
        (
            [id] => 76
            [title] => 
            [tagid] => 
            [published] => 1
            [uparent] => 10318
            [parent] => 71
            [flags] => 
            [secip] => 188.170.83.5
            [sechash] => a67998a27f377eeaba9be7c881b9cca1
            [content] => лучше не мочить, это мягкая игрушка
            [mode] => 0
            [createdby] => 17
            [createdon] => 1511112012
            [editedby] => 0
            [editedon] => 0
            [deleted] => 0
            [deletedon] => 0
            [deletedby] => 0
            [publishedon] => 0
            [publishedby] => 0
            [rating] => 0
            [custom] => Array
                (
                )
       ) 

Повторюсь - ajax тут реализован не очень. Но пока руки не доходят поменять. Было б под Revo - был бы стимул. Просто на Evo все меньше клиентов. В принципе - работает и так. Ну и пусть. Хотя, конечно, немного напрягает. Руки так и чешутся. Может как-нибудь соберусь.

git автора https://github.com/Temus/JotX

Довольно мощная и добротная штука. Очень гибкая. Но без погружения в исходники мне было не разобраться. Мало примеров и мало документации. Есть дополнения, которые при освоении разочаровывают. JotX - наоборот. Сначала слегка разочаровал, но по мере освоения - приятно удивил продумманостью и гибкостью. Единственная заморочка - это почта. Ну это я для себя лично решил. Если пользоваться только доками - врядли это поможет полноценно использовать это разширение. Так для обработчиков событий передаются 2 параметра. 1-й - сам текущий объект JotX, 2-й - масиив параметров. И этот массив для каждого события свой. И чтобы узнать содержимое этого массива - приходится лезть в исходники. Есть свой парсер для обработки своих шаблонов(TPL), где уже встроен PHx.


Комментарии 0






Разрешённые теги: <b><i><br>Добавить новый комментарий: