Облако тегов для miniShop2
UPDATE 20.03.2018: Сниппет обновлён на корректный и добавлен pdoTools для обработки чанка.
Появилась задача реализовать облако тегов для удобства поиска товаров в интернет-магазине. Для этого сделал простенький сниппет, где теги собираются со всех товаров на сайте.
Сниппет умеет принимать параметры базового размера(font), шага в пикселях(step), количества размеров(levels) и чанка для вывода(tpl).
Алгоритм работы прост:
1. Собираются теги со всех товаров сайта.
2. Подсчитывается количество товаров для каждого тега.
3. Рассчитываются размеры для каждого уровня и границы по количеству использования тега.
4. Если не указан шаблон вывода, то на экране также будет облако тегов, но без ссылок.
В чанке для вывода доступны плейсхолдеры:
Вызывать так:
Сам сниппет msCloudTags:
P.S.: У сайта на скриншоте товары только добавляются, большинство тегов используются 1-3 раза, а те, что крупные, больше 20 раз.
P.P.S.: Наверняка, код можно написать покороче и лучше, но я совсем недавно начал работать на MODX. Буду рад вопросам и замечаниям :)
UPDATE 20.03.2018: Сниппет обновлён на корректный и добавлен pdoTools для обработки чанка.
Появилась задача реализовать облако тегов для удобства поиска товаров в интернет-магазине. Для этого сделал простенький сниппет, где теги собираются со всех товаров на сайте.
Сниппет умеет принимать параметры базового размера(font), шага в пикселях(step), количества размеров(levels) и чанка для вывода(tpl).
Алгоритм работы прост:
1. Собираются теги со всех товаров сайта.
2. Подсчитывается количество товаров для каждого тега.
3. Рассчитываются размеры для каждого уровня и границы по количеству использования тега.
4. Если не указан шаблон вывода, то на экране также будет облако тегов, но без ссылок.
В чанке для вывода доступны плейсхолдеры:
[[+fontlevel]] //число от 0 до levels, можно использовать для класса level1, level2
[[+tag]] // сам тэг
[[+fontsize]] // размер в пикселях
Вызывать так:
[[msCloudTags? &tpl=`tpl.tag` &font=`13` &step=`2` &levels=`10`]]
Сам сниппет msCloudTags:
<?php
if (!isset($step)) {$step = 2;} // шаг в пикселях
if (!isset($font)) {$font = 12;} // начальный размер шрифта
if (!isset($levels)) {$levels = 10;} // максимальное число уровней
if (!isset($key)) {$key = 'tags';}
if (!isset($tpl)) {$tpl = '@INLINE <span class="level{$fontlevel}" style="font-size:{$fontsize}px;">{$tag}</span>;';}
$pdo = $modx->getService('pdoTools');
$q = $modx->newQuery('msProductOption');
$q->innerJoin('modResource','modResource','modResource.id = msProductOption.product_id');
$q->where(array('msProductOption.key' => $key));
$q->select(array('msProductOption.value'));
$q->sortby('msProductOption.value','ASC');
$tags = array();
if ($q->prepare() && $q->stmt->execute()) {
while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
$tags[]= $row['value'];
}
}
$tagsCount = array_count_values($tags); // массив с подсчитанным вхождением
$maxCount = max($tagsCount); // максимальное количество вхождений
$minCount = min($tagsCount); // минимальное
$fontSizes[] = $font;
for ($i=0;$i<$levels;$i++) {
$fontSizes[] = $font+=$step;
}
$fontLevels[] = $minCount;
$stepCounts = ($maxCount-$minCount)/$levels;
for ($i=0;$i<$levels;$i++) {
$fontLevels[] = (int)($minCount+=$stepCounts);
}
$fontsize = $fontSizes[0];
$result='';
foreach ($tagsCount as $tag => $count) {
for ($i=$levels;$i >= 0;$i--) {
if ($count >= $fontLevels[$i]) {
$fontsize = $fontSizes[$i];
$fontlevel = $i;
break;
}
}
$result.= $pdo->getChunk($tpl, array(
'fontlevel' => $fontlevel,
'tag' => $tag,
'fontsize' => $fontsize
));
}
return $result;
P.S.: У сайта на скриншоте товары только добавляются, большинство тегов используются 1-3 раза, а те, что крупные, больше 20 раз.
P.P.S.: Наверняка, код можно написать покороче и лучше, но я совсем недавно начал работать на MODX. Буду рад вопросам и замечаниям :)
UPDATE 20.03.2018: Сниппет обновлён на корректный и добавлен pdoTools для обработки чанка.
Поблагодарить автора
Отправить деньги
Комментарии: 24
В сниппете можно навести красоту, но и в таком виде хорошо читается.
Евгений, собери пакет из этого? ;)
Евгений, собери пакет из этого? ;)
Может имеет смысл запилить что-то вроде gists (github) для коллекции подобного рода сниппетов/решений? Пакет для такого собирать — оверхед (я конфиг сборки как правило вдумчиво пишу с нуля, чтобы ничего лишнего). Так, мысли в слух
Иван, уж если в репо есть компонент If, то это точно имеет право на жизнь, дабы парой кликов поставить на сайт без лишних телодвижений.
Да и компонент собрать не так уж сложно. На мой взгляд, конечно :)
Да и компонент собрать не так уж сложно. На мой взгляд, конечно :)
Пакет из сниппета и пары чанков можно собрать PackMan'ом — просто и быстро
Про PackMan не знал, спасибо, Илья!
Но я думаю пока рановато собирать пакет из одного сниппета :)
Это будет иметь смысл, когда понадобится больше функционала.
Например, выбор категорий, для которых нужно вывести теги, количество товаров рядом с тегом и что-то ещё.
Может даже можно будет приделать сферический 3D режим облака тегов.
Если будет спрос на это, то допишу и упакую в бесплатный пакет)
Но я думаю пока рановато собирать пакет из одного сниппета :)
Это будет иметь смысл, когда понадобится больше функционала.
Например, выбор категорий, для которых нужно вывести теги, количество товаров рядом с тегом и что-то ещё.
Может даже можно будет приделать сферический 3D режим облака тегов.
Если будет спрос на это, то допишу и упакую в бесплатный пакет)
Есть смысл. Если не в modstore, то хотя бы в modx.com. Правда, гораздо проще установить, чем копировать код
Так собери пакет уже сейчас, хотя бы с modExtra и выложи. Ведь у всех решения кастомные, а у тебя получилось более менее общее — можно будет с лёгкостью форкнуть и дописать под свои нужды!
Тем более раз там 1 сниппет и чанк вывода тэгов, плюс для людей, которые не особо знакомы с MODX будет хорошо: кликнул — > установил -> вызвал -> profit.
Тем более раз там 1 сниппет и чанк вывода тэгов, плюс для людей, которые не особо знакомы с MODX будет хорошо: кликнул — > установил -> вызвал -> profit.
если к этому еще и динамическую генерацию страниц с транслитом добавить, спрос точно будет) и сниппет уже не один.
чтобы не site.com/?tags=хоп%20%хей, а site.com/tags/hop-hei
чтобы не site.com/?tags=хоп%20%хей, а site.com/tags/hop-hei
А как выводите с ссылками?
С msearch2 просто обернул ссылкой
С msearch2 просто обернул ссылкой
<a href="[[~25]]?query=[[+tag]]">tpl</a>
Вот чанк вывода, который используется на скриншоте:
Где 68 — это страница каталоге, на который вызывается mFilter2 и прописан aliases: msoption|tags==tags.
Но можно сделать чтобы работало и по адресу /tags/[[+tag]] с помощью собственной маршрутизации.
<a class="tag tag[[+fontlevel]]" href="[[~68]]?tags=[[+tag]]" style="font-size:[[+fontsize]]px;">[[+tag]]</a>
Где 68 — это страница каталоге, на который вызывается mFilter2 и прописан aliases: msoption|tags==tags.
Но можно сделать чтобы работало и по адресу /tags/[[+tag]] с помощью собственной маршрутизации.
Мой вариант облака тегов:
$tpl = 'tpl.Tag'; //чанк одного тега
$tags = array(); // массив тегов
$params = array();// массив параметров
$per = 75; // начальный % шрифта
$output=''; //вывод
$c = $modx->newQuery('msProductOption');
$c->where(array('key' => 'tags')); //берём значения тегов
$c->sortby('value','ASC');
$options = $modx->getCollection('msProductOption',$c);
foreach($options as $option){
$tags[] = $option->get('value');
}
$tags = array_count_values($tags); //подсчитываем сколько одинаковых
//выводим в чанк
foreach($tags as $tag => $count){
$params['tag'] = $tag;
$params['href'] = '?tag=' . $tag;
$params['fontsize'] = $per*$count;
$output .= $modx->getChunk($tpl,$params);
}
return $output;
Чанк:<li><a href="[[~41]][[+href]]" style="font-size:[[+fontsize]]%;">[[+tag]]</a></li>
Вывод товаров по тегу (нашел у Василия):$tag = $_GET['tag'];
$key = 'tags'; // имя опции товара
$category = 0; // фильтрация по категории
$q = $modx->newQuery('msProductOption');
$q->innerJoin('msProduct', 'msProduct', 'msProduct.id=msProductOption.product_id');
$q->where(array('msProductOption.key' => $key, 'msProductOption.value'=> $tag));
$q->sortby('msProductOption.value','ASC');
$q->select('DISTINCT(msProductOption.value), msProduct.id');
$q->where(array('msProductOption.key' => $key));
if (!empty($category)) {
$ids = $modx->getChildIds($category);
$ids[] = $category;
$q->innerJoin('msCategory', 'msCategory', 'msCategory.id=msProduct.parent');
$q->where(array('msCategory.id:IN' => $ids));
}
$result = array();
if ($q->prepare() && $q->stmt->execute()) {
while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
$res['id'][] = $row['id'];
}
$result = implode(",", array_unique($res['id'])) ;
}
$params = array(
'includeThumbs' => '148x148',
'parents' => 2,
'tpl'=> 'tpl.msProducts.News.row',
'resources' => $result
);
$output = $modx->runSnippet('msProducts', $params);
return $output;
Добрый день!
Подскажите, а как сделать несколько уровней, или остановить увеличение шрифта? Чем больше используется тег, тем больше шрифт. Спасибо!
Подскажите, а как сделать несколько уровней, или остановить увеличение шрифта? Чем больше используется тег, тем больше шрифт. Спасибо!
Добрый день!
Вопрос наверно не мне задан, но если будете использовать код из заметки, то там есть ограничение на максимальное число уровней)
Вопрос наверно не мне задан, но если будете использовать код из заметки, то там есть ограничение на максимальное число уровней)
Евгений, добрый день!
Ваш код из заметки почему-то не работает. Возможно, вы выводите через mFilter2, а я вывожу без него. Вы не подскажите, как вывести товары через ваше облако тегов. Вывод товаров по тегу на странице не работает.Спасибо.
Ваш код из заметки почему-то не работает. Возможно, вы выводите через mFilter2, а я вывожу без него. Вы не подскажите, как вывести товары через ваше облако тегов. Вывод товаров по тегу на странице не работает.Спасибо.
Поправил сниппет в заметке — попробуйте :)
Нет, при клике на тег выводит все товары, а не те товары у которых данный тег. Вывожу вот так:
<a class="tag tag[[+fontlevel]]" href="[[~26]]?tags=[[+tag]]" style="font-size:[[+fontsize]]px;">[[+tag]]</a>
На странице вызова вывод товаров из последнего комментария. Может что не так делаю?
Вот такую ссылку надо:
href="[[~26]]?tag=[[+tag]]"
Заработало!!! Евгений, спасибо большое за помощь!
Евгений, добрый день!
Не могу вывести товары по тегу, через PdoPage, со страницами. Просто когда один тег у сотни товаров, они выводятся все. Вы не подскажите, как вывести товары со страницами?
Не могу вывести товары по тегу, через PdoPage, со страницами. Просто когда один тег у сотни товаров, они выводятся все. Вы не подскажите, как вывести товары со страницами?
Добрый день!
Вывод, конечно, не зависит от облака тегов.
Но стандартный вызов pdoPage должен решить проблему:
Но если сильно привязались к решению из комментария, то вместо этого:
Вывод, конечно, не зависит от облака тегов.
Но стандартный вызов pdoPage должен решить проблему:
[[!pdoPage?
&element=`msProducts`
&optionFilters=`[[!#GET.tag:notempty=`{"tags":"[[!#GET.tag]]"}`]]`
&limit=`10`
//ваши параметры какие угодны
]]
[[!+page.nav]]
Но если сильно привязались к решению из комментария, то вместо этого:
$params = array(
'includeThumbs' => '148x148',
'parents' => 2,
'tpl'=> 'tpl.msProducts.News.row',
'resources' => $result
);
$output = $modx->runSnippet('msProducts', $params);
return $output;
напишитеreturn $result;
и уже вызов этого сниппета вставьте в resources[[!pdoPage?
&element=`msProducts`
&resources=`[[!вашСниппет]]`
//...
]]
Евгений, спасибо за Вашу помощь!!!
Но я пытаюсь вывести на Fenom. Ничего не получается :( Наверное ошибаюсь в синтаксисе.
Но я пытаюсь вывести на Fenom. Ничего не получается :( Наверное ошибаюсь в синтаксисе.
Возможно, попробуйте все варианты, всё получится!)
Я тоже могу ошибаться, например в optionFilter или ещё где-то :)
Я тоже могу ошибаться, например в optionFilter или ещё где-то :)
Добрый день!
Вообщем решил так:
Спасибо Вам за помощь!!!
Вообщем решил так:
<?php
$tag = $_GET['tag'];
$key = 'tags'; // имя опции товара
$category = 0; // фильтрация по категории
$q = $modx->newQuery('msProductOption');
$q->innerJoin('msProduct', 'msProduct', 'msProduct.id=msProductOption.product_id');
$q->where(array('msProductOption.key' => $key, 'msProductOption.value'=> $tag));
$q->sortby('msProductOption.value','ASC');
$q->select('DISTINCT(msProductOption.value), msProduct.id');
$q->where(array('msProductOption.key' => $key));
if (!empty($category)) {
$ids = $modx->getChildIds($category);
$ids[] = $category;
$q->innerJoin('msCategory', 'msCategory', 'msCategory.id=msProduct.parent');
$q->where(array('msCategory.id:IN' => $ids));
}
$result = array();
if ($q->prepare() && $q->stmt->execute()) {
while ($row = $q->stmt->fetch(PDO::FETCH_ASSOC)) {
$res['id'][] = $row['id'];
}
$result = implode(",", array_unique($res['id'])) ;
}
$params = array(
'element' => 'msProducts',
'includeThumbs' => '260x195',
'parents' => 9,
'limit' => 21,
'tpl'=> 'tpl.msProducts.new',
'ajaxMode' => 'default',
'tplPageWrapper' => '@INLINE <ul class="pagination uk-pagination">{{+prev}}{{+pages}}{{+next}}</ul>',
'tplPageActive' => '@INLINE <li class="uk-active"><span>{{+pageNo}}</span></li>',
'resources' => $result
);
$output = $modx->runSnippet('pdoPage', $params);
return $output;
И вывод на странице:<div id="pdopage">
<div class="rows uk-child-width-1-3@s uk-grid-match" uk-grid>
{'!Tags' | snippet}
</div>
<div class="uk-panel uk-panel-box uk-flex uk-flex-center">{'page.nav' | placeholder}</div>
</div>
Все работает.Спасибо Вам за помощь!!!
Спасибо огромнейшее!
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.