Мультитеги для Tickets
Продолжаем тему с тегами. В прошлой статье мы рассмотрели простую систему тегов — 1 тег для одного тикета (ресурса). В этой статье я покажу как к тикету привязать несколько тегов.
Количество шагов будет такое же, но многое придется изменить.
1. Расширяем таблицу ресурсов
Через phpMyAdmin создаем поле tags в таблице modx_site_content
. Длину зададим побольше, так как в нём мы будем хранить несколько тегов.
Тип: varchar Длина: 250
2. Создаем TV
В дереве ресурсов создаем TV с именем tv.tags и типом ввода «Список (множественный выбор)». Дальше нужно привязать его к шаблону, который используется для тикетов. Добавляем теги для списка в формате TAG==TAG
и объединяем их через две вертикальные черты (||).
Можете указать значение по-умолчанию, если нужно.
3. Плагин для сохранения тегов
Создаём плагин с любым именем на события «OnMODXInit» и «OnDocFormSave».
<?php switch ($modx->event->name) { case 'OnMODXInit': // Загружаем наше поле в модель ресурса $modx->loadClass('modResource'); $modx->map['modResource']['fields']['tags'] = ''; $modx->map['modResource']['fieldMeta']['tags'] = array( 'dbtype' => 'varchar', 'precision' => 200, 'phptype' => 'string', 'null' => false, 'default' => '', ); break; case 'OnDocFormSave': // Сохраняем ТВ в поле таблицы ресурса $tv = $modx->getObject('modTemplateVar', array('name' => 'tv.tags')); $fields = array( 'tmplvarid' => $tv->get('id'), 'contentid' => $resource->get('id'), ); if ($tvr = $modx->getObject('modTemplateVarResource', $fields)) { $tv = str_replace('||',',',$tvr->get('value')); $resource->set('tags', $tv); } else { $resource->set('tags', ''); } $resource->save(); break; }
4. Сниппет для вывода тегов
Как и в предыдущей статье создаём сниппет getTags
, который будет выводит теги с количеством статей.
<?php // При вызове сниппета указываем параметр $parent - секция тикетов, в котором считать тикеты. $parent = $modx->getOption('parent', $scriptProperties, 0); $q = $modx->newQuery('modResource'); $q->where(array('parent' => $parent,'published'=>1)); $q->select('tags'); if ($q->prepare() && $q->stmt->execute()) { $res = $q->stmt->fetchAll(PDO::FETCH_ASSOC); } $_tags = $tags = array(); foreach($res as $row){ if (!empty($row['tags'])) { $_tags = array_merge($_tags,explode(',',$row['tags'])); } }; // Подсчитываем количество foreach($_tags as $tag) { if (isset($tags[$tag])) { $tags[$tag]++; } else { $tags[$tag] = 1; } } // Сортируем ksort($tags); $pls = ''; // Формируем список if (!empty($tags)) { $pls .= '<ul>'; foreach($tags as $tag=>$count){ $url = $modx->makeUrl($parent, '', array('tag' => $tag)); $pls .= "<li><a href=\"{$url}\"><i class=\"fa fa-tag\"></i> {$tag} ({$count})</a></li>"; }; $pls .= '</ul>'; } return $pls;
Вставляем вызов сниппета в нужное место. Я это делаю в сайдбаре.
// В parent указываем контейнер с тикетами [[!getTags? &parent=`10`]]
5. Фильтруем тикеты
Теперь поправим сниппет-обертку getFilteredTickets
. Так как поиск немного усложнился, то нужно переписать условие where
.
<?php $tag = isset($_GET['tag']) ? $modx->sanitizeString($_GET['tag']) : ''; if ($tag) { $where = '["FIND_IN_SET(' . $modx->quote($tag) . ', `Ticket`.`tags`) > 0"]'; $scriptProperties = array_merge($scriptProperties, ['where' => $where]); } return $modx->runSnippet('getTickets', $scriptProperties);
Теперь в разделе с тикетами в табе «Настройки раздела» (страница с типом ресурса «Раздел с тикетами») нужно указать этот сниппет.
[[!pdoPage? &element=`getFilteredTickets` ]] [[!+page.nav]]
Чтобы вызвать в произвольном месте, используем такой вызов
// Указываем необходимые параметры сниппета getTickets [[!pdoPage? &element=`getFilteredTickets` &parents=`5` ]] [[!+page.nav]]
Всё. Подготовка закончена.Теперь при создании тикета ему можно указывать несколько тегов.
6. Вывод похожих тикетов
Ну и напоследок решим задачу вывода похожих тикетов. Для этого мы напишем сниппет, который будет выводить тикеты, у которых есть такие же теги как у текущего.
<?php // Сниппет getRelatedTickets // Сниппет будет работать только для тикетов. if ($modx->resource->get('class_key') != 'Ticket') return ''; $tags = $modx->resource->get('tags'); if (empty($tags)) return ''; $tags = explode(',', $tags); $where = ''; foreach($tags as $tag){ if (!empty($where)) $where .= ' OR '; $where .= 'FIND_IN_SET(' . $modx->quote($tag) . ', `tags`) > 0'; } if (!empty($where)) $scriptProperties = array_merge($scriptProperties, ['where' => $where]); return $modx->runSnippet('pdoResources',$scriptProperties);
Ну а дальше дело за малым — нужно вызвать этот сниппет:
[[!getRelatedTickets? &tpl=`@INLINE <li><a href="[[+uri]]">[[+pagetitle]]</a></li>` &select=`pagetitle,uri` &parents=`0` // Без ограничений &resources=`-[[*id]]` // Исключаем текущий тикет &limit=`0` // Выводим все найденные тикеты &class=`Ticket` ]]
Решение, описанное в этой статье, работает на этом сайте. Можно проверить прямо на этой страничке.
Комментарии ()
Вы должны авторизоваться, чтобы оставлять комментарии.
Подумал, что можно так, с помощью stripTags:
А дальше, как по каждому элементу массива выбрать все подходящие тикеты – не хватает знаний)
Есть пример с использованием TV полей:
Правда не знаю, в тему ли вообще этот пример.)
Например у этой статьи в мета видны теги «MODX, Tickets, Тэги».
Как это сделать?