Плагін TagSaver для роботи з тегами.
Взагалі, фільтрація по тегам в MDOX реалізується доволі кисло. Уявіть, у вас є якись TV параметр, в якому у вас до кожної статті прописано по 10 тегів.
А в базі всі ці теги для документа зберігаються в одній стрічці. Тобто виглядає це приблизно так
modx, теги, робота з тегами, сортування за тегами
Як зазвичай відбувається сортування? Створюється SQL запит в таблицю site_tmplvar_contentvalues з використанням WHERE value LIKE %тег%
Таким чином, ми можемо шукати не тільки по тим тегам, які задумувались автором сайта, а й по тегам
Більш того, якщо документів дуже багато, то пошук відбувається неймовірно довго. Як взагалі ідеально повинна виглядати робота з тегами?
Таблиця з документами вигляду: id, content, pagetitle
Таблица з тегами: id, tag
Таблица зв'язків з тегами: doc_id, tag_id
Можна звісно довго спорити про необхідності таблиці звязку, Оскільки придеться робити лишній JOIN. Але щодо правильно розставлених індексів цей джоін взагалі непомітний. Більш того, трохи завершивши таблицю ми можемо вписувати теги в декількох TV-шках, а зберігати в одній таблиці по вищеописаному стандарту.
На основі всього вищесказаного у нас получаються вот такі 2 таблиці
DROP TABLE IF EXISTS `modx_site_content_tags`; CREATE TABLE `modx_site_content_tags` ( `doc_id` int(11) NOT NULL, `tag_id` int(11) NOT NULL, `tv_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`tag_id`,`doc_id`,`tv_id`), UNIQUE KEY `dtt` (`doc_id`,`tag_id`,`tv_id`) USING BTREE, KEY `doc_id` (`doc_id`), KEY `tag_id` (`tag_id`), KEY `tv_id` (`tv_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `modx_tags`; CREATE TABLE `modx_tags` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Як видно, формат у таблиць MyISAM. Але у такого вибору є своя причина. Одна з них це auto_increment. А друга – унікальний ключ по декільком полям. Не буду довго затримуватись на цьому пункті. Скажу одне – якщо у вас MODX встановлений з префіксом таблиць відмінним від modx, то поміняйте його на свій;-)
Все дуже просто. Створіть як зазвичай TV параметр. Можете навіть додати віджет mm_widget_tags від ManagerManager. Після цього створіть плагін TagSaver з параметрами
&tv=ID TV-параметра;input; &sep=Роздільник тегів;input;
Якщо роздільника немає, то можна залишити порожнім.
Створіть копію плагіна з іншим іменем з аналогічними параметрами. Тільки не забудьте в новій версії плагіна вказати роздільник і ID другого TV параметра.
Виводити їх можна як і раніше – через сніпети DocInfo, просто демонструючи TV параметр на сторінці .
Очень просто. Створіть сніпет приблизно з таким вмістом
$tag = ((isset($tag) && is_scalar($tag))? $tag : (isset($_GET['tag']) && !is_array($_GET['tag']) ? $_GET['tag'] : '')); $id = isset($id) ? (int)$id : 0; $out = array(); if($id>0 && $tag!=''){ $sql=$modx->db->query("SELECT doc_id FROM ".$modx->getFullTableName("tags")." as t LEFT JOIN ".$modx->getFullTableName("site_content_tags")." as ct ON ct.tag_id = id WHERE t.`name`='".$modx->db->escape($tag)."' AND ct.tv_id={$id}"); $sql=$modx->db->makeArray($sql); foreach($sql as $item){ $out[]=$item['doc_id']; } } return implode(",",$out);
І результат роботи цього сніпета передаєте в параметр documents від Ditto. У сніпета вказаного вище є 2 параметра:
Виходить приблизно так
[[Ditto? &documents=`[!GetTag? &id=`2`!]`]]
$count = isset($count) ? (int)$count : 10; $tv = isset($tv) ? (int)$tv : ''; $out = array(); $sql = $modx->db->query( "SELECT ct.tv_id,t.name,count(ct.tag_id) as count FROM ".$modx->getFullTableName("tags")." as t LEFT JOIN ".$modx->getFullTableName("site_content_tags")." as ct ON ct.tag_id=t.id LEFT JOIN ".$modx->getFullTableName("site_content")." as c on c.id=ct.doc_id WHERE deleted=0 AND published=1 ".(($tv!='') ? ("AND ct.tv_id=".$tv) : "")." GROUP BY tag_id ORDER BY count(ct.tag_id) DESC LIMIT 0,".$count ); $sql = $modx->db->makeArray($sql); foreach($sql as $item){ $out[]=$modx->parseChunk($tpl,$item,"[+","+]"); } return implode((isset($outSep) ? $outSep : ""),$out);
У сніпета є 3 параметра
<a href="/11.html?tag=[[urlencode? &input=`[+name+]`]]" title="Статті з тегом [+name+]" class="label">[+name+] ([+count+])</a>
Як бачимо, цей сніпет не тільки теги підставляє, але ще й считує скільки разів вони використовуються. Таким чином виклик сніпета для хмари тегів виглядає так:
[[TagCloud? &tpl=`TagCloudItem` &tv=`7` &count=`20`]]
return isset($input) ? urlencode($input) : '';
Для чого він потрібний найдете в гуглі
В силу того, що мені доволі часто приходиться працювати з сайтами зробленими іншими програмістами, то можу сказати вам одне – таких рішень ще ніде не було. Всі сортують за страрими стандартами Ditto і винаходять свої велосипеди у вигляді екстендерів для нього. Моє рішення дозволяє вам працювати з видимою частиною також, як і раніше. Проте суттєво знімає навантаження на сервер при сортуваннях. І полегшує вибірку, навіть, якщо ви використовуєте знаменитий сніпет DropDownDocs для прив'язки статей до декількох розділів (адже по суті це також теги, тільки вигляд з боку). Відповідно, якщо вам потрібні теги й сортування за параметрам TV в значенні котрих може бути декілька даних – використовуйте TagSaver.
Автор: Agel_Nash