Этот код выводит иерархический (!) список терминов определённого словаря.
Каждый термин является ссылкой на страницу с анонсами статей, принадлежащих этому термину.
Рядом с каждым термином выводится количество документов.
Если документов нет, то нуль не выводится и название термина не является ссылкой.
Оригиналный код содержал ошибку, которая не позволяла выводить списки с большим разбросом глубины. То есть при резком изменении глубины терминов скрипт это не обрабатывал и теги оставались не закрытыми. В этом коде это исправлено:
$vid = 3; // Номер словаря
$pole = array();
$items = array();
$terms = taxonomy_get_tree($vid);
//var_dump($terms);
foreach ( $terms as $term ) {
$count = db_result(db_query("SELECT COUNT(nid) FROM {term_node} WHERE tid = %d", $term->tid));
$pole[]=Array ((($count) ? l($term->name, "taxonomy/term/$term->tid")." (".$count.")" : $term->name), $term->depth, $count, $term->tid);
}
$depth =-1;
foreach ($pole as $list) {
//$depth- глубина предыдущего уровня
//$list[1] - глубина текущего элемента
if ($list[1] == $depth) {
echo "";
next;
}
while ($list[1] != $depth) {
if ($list[1] > $depth) {
$depth++;
echo "\n
- ";
next;
}
if ($list[1] < $depth) {
$depth--;
echo "\n\n
";
}
}
echo "\n
$depth=$list[1];
}
//Закрываем все открытые теги до нулевого уровня:
$depth=0;
while ($list[1] != $depth) {
if ($list[1] > $depth) {
$depth++;
echo "
\n";
}
}
?>
Комментарии
Решение было сохранено на сайте DrupalCookBook.ru:
Список терминов определённого словаря с иерархией + количество документов.
Авторы, предложившие решения, также указаны в сохранённой статье.
Отличная работа, спасибо! Утащил в закрома.
На практике, имеет значение, как количество уровней, так и количество элементов на каждом уровне. Если на каком-то уровне слишком много элементов - вертикальный список приходится заменять горизонтальным перечислением. А также регулировать болдом шрифта. Пример: http://newtariffs.ru/regions
Было бы здорово создать такой скрипт, где, начиная с определенного уровня, список заменялся бы на br
Подскажите, пожалуйста, как вертикальный список перевести в горизонтальное перечисление. Так как у вас это сделано здесь http://newtariffs.ru/regions
Где вносить правку, в сниппет или в стилевой файл.
Спасибо.
Я вносил в сниппет. Думаю, и через стили можно сделать.
Скажите, что нужно изменить в сниппете, чтобы последний уровень словаря шел горизонтально. Как у вас сделано для "город Москва, город Белогород" и так далее.
+1, Goodboy, расскажите
У меня нет готового универсального сниппета. Есть "наколеночный" сниппет для терминов конкретного словаря.
Я не проверял, но думаю, что можно воспользоваться сниппетом этого топика+CSS
На самом деле для подсчета количества нодов у словаря есть такая прекрасная, системная вещь:
<?php
$nodes=taxonomy_term_count_nodes($term->tid);
?>
Просто у Вас запрос написан без
<?php
$query = db_rewrite_sql($query);
?>
и поэтому результат может оказаться не корректным. Например, будут считаться не опубликованные ноды.
Отличный сниппет.
А как-бы разбить результат на 3-4 колонки?
А то у меня очень много терминов в словаре.
Я честно говоря использую немного другой код для вывода списка терминов. Он кстати сразу подразумевает вывод в несколько колонок.
$vid = 1; // Номер словаря
$num_cols = 2; // Количество колонок
$show_pic = module_exists('taxonomy_image');
$items = array();
$depth =-1; //глубина
$terms = taxonomy_get_tree($vid, 0, $depth, 1);
foreach ( $terms as $term ) {
$count = taxonomy_term_count_nodes($term->tid);
if ($show_pic) { $pic = taxonomy_image_display($term->tid /*, 'align="left"'*/); }
else {$pic = NULL; }
$name_and_count = l($pic . $term->name,'taxonomy/term/'.$term->tid, NULL, NULL, NULL, NULL, TRUE)." (".$count.")
".$term->description;
$items[] = $name_and_count .'
';
} /* end foreach */
if (count($items)) {
if ($num_cols == 1) {
echo theme('item_list', $items);
}
else {
$slice = ceil(count($items) / $num_cols);
echo '
for ($i = 0; $i < $num_cols; ++$i) {
$start = $i * $slice;
$class = $i % 2 ? 'even' : 'odd';
echo '
echo theme('item_list', array_slice($items, $start, $slice));
echo '
';
}
echo '
';
}
}
else { echo 'Ни одной категории не найдено'; }
?>
Kalian ваш код хороший. Работает быстрее. Только не показывает внутренности таксономии. т.е. если боьше одного термина в подкатегории то он их не выводит.
Буду делать из двух один. Спасибо
evova, просто я вывожу список подкатегорий на странице самой категории. Размещаю там такой же блок, только глубину меняю.
ок Понял - будем разбираться.
Спасибо
спасибо, полезно
Эту задачку и проще можно решить:
<?php
$vid = 1; // vid словаря термины из которого выводим
$tree = taxonomy_get_tree($vid);
foreach ($tree as $term) {
$depth = "";
for($i = 0; $i <= $term->depth; $i++)$depth .= "-";
print $depth . $term->name . " [" . $term->tid . "]
";
}
?>
Не стал заморачиваться с аутпутом, но символы "--" легко заменить на ul-li.
Также можно начать выводить термины с определенного родителя, подробности тут: http://api.drupal.org/api/function/taxonomy_get_tree/6
Я, кстати, год назад, примерно такие же фии выкладывал
Если кому понадобиться, нашел еще один способ вывода иерархии.
<?php
$vid = 1; /* <---- put correct vocabulary ID here */
$terms = taxonomy_get_tree($vid);
print "
";- ";
foreach ( $terms as $term ) {
$tcount = taxonomy_term_count_nodes($term->tid);
$children_terms = taxonomy_get_children($term->tid);
if ($term->depth == 0) {
print "
print l($term->name." (".$tcount.")",'taxonomy/term/'
.$term->tid, array('title' => $tcount." posts in "
.$term->name));
if ($children_terms) {
print "
";- ";
foreach ( $children_terms as $children_term ) {
$t_children_count =
taxonomy_term_count_nodes($children_term->tid);
print "
print l($children_term->name." (".$t_children_count.")",
'taxonomy/term/'.$children_term->tid, array('title' =>
$t_children_count." posts in ".$children_term->name));
print "
";
}/* end foreach children */
print "
";
}
print "
";
}
} /* end foreach */
print "
";
?>
Чтобы вывести список по горизонтали (Пример: http://newtariffs.ru/regions) не обязательно код скрипта переписывать.
Это можно и нужно делать стилями.
Примерно так:
А глубину вложенности можно установить так:
Угловая скобка обозначает, что один элемент идущий сразу за другим. Хотя я не силён в стилях...
VladSavitsky,
Насчет стилей, IMHO, это не совсем прямой путь.
Я просто призываю сделать более универсальный скрипт. В котором, например, первый уровень имел бы "разделители" ol, второй уровень - ul, третий был по горизонтали ( br или p )...
VladSavitsky
Если уж заговорили о css, то ваш вариант, выводит весь список в одну строку, но никак не разбивает их на столбцы.
Если кто-то не захочет менять код стандартного блока, то можно воспользоваться этим примером. Там рассказывается как сделать вывод в несколько столбцов с помощью ксс.
Вывод 3го уровня в виде текста по горизонтали легче сделать стилями, чем ковырять код. Хотя я более уверенно себя чувствую в РНР, чем в CSS.
Есть масса решений того, как список вывести и колонками и просто по горизонтали как текст. И Kalian привёл хороший пример этому.
VladSavitsky, ваш пример мне нравится гораздо больше, чем вариант Kalian тем, что выполняется гораздо быстрее. А классически обход дерева выполняется рекурсией, но вот сколько это сожрет ресурсов...
VladSavitsky, еще раз спасибо за скрипт, я возьму его за основу.
"Каждый термин является ссылкой на страницу с анонсами статей, принадлежащих этому термину"
Хм..А как формируются эти страницы? Можно ли как-то настроить их адреса, или изменить структуру?
Подскажите, пожалуйста. Я совсем недавно начал изучать друпал...
Хочу использовать этот замечательный сниппет для вида taxonomy/vocabulary. С views вроде разобрался (2 аргумента - Taxonomy: Vocabulary ID и Taxonomy: Term Name, "Использовать текст, если пусто", текст - код сниппета), подскажите только, что изменить в
<?php
$vid = 3;
?>
или в
<?php
$terms = taxonomy_get_tree($vid);
?>
, чтобы номер словаря определялся автоматически (словарей несколько).
Если адреса у Вас будут иметь такой вид:
taxonomy/vocabulary/1
taxonomy/vocabulary/2
taxonomy/vocabulary/3
то используйте функцию arg(2)
для адреса taxonomy/vocabulary/1
arg(0)=='taxonomy'
arg(1)=='vocabulary'
arg(2)=='2'
Можно сделать так, чтобы считались только опубликованные документы, и при отсутствии таковых термин вообще не выводился? а если есть опубликованные и неопубликованные ноды, чтобы в скобках выводилось число только опубликованных.
А можно поподробней как менять глубину? Чтобы на главной странице отображались только категории верхнего уровня без подкатегорий?
Для этого нужно $terms = taxonomy_get_tree($vid);
заменить на $terms = taxonomy_get_tree($vid, 0, -1, 1);
Подробности taxonomy_get_tree
Спасибо, полезный материал
$depth=0;
while ($list[1] != $depth) {
if ($list[1] > $depth) {
$depth++;
echo "</li>\n</ul>";
}
}
В комментарии написано, что код закрывает теги, но у меня он не работает(ну или что-то типа того ,я не знаю пхп). Последние li ul не закрыты.
Заменил код на
и все стало нормально
Как сделать выбор номера словаря автоматически?
И снова комент)) еще можно вопрос? вот что нужно поменять в коде,имея такой словарь:
словарь: сочинения
сочинения укр
-шевченко
-франко
-глибов
сочинения рус
-пушкин
-лермонтов
чтоб на страницу выводило пункты меню "сочинения укр" и "сочинения рус"
пользуясь кодом приведенным вначале?
ех.. сам нашел решение.(PHP еще не учил). из кода представленного
убрал foreach children. Конечно, для программистов и так понятно)) но для других..
и вышло:
<?php
$vid = 1; /* <---- put correct vocabulary ID here */
$terms = taxonomy_get_tree($vid);
print "
";- ";
foreach ( $terms as $term ) {
$tcount = taxonomy_term_count_nodes($term->tid);
$children_terms = taxonomy_get_children($term->tid);
if ($term->depth == 0) {
print "
print l($term->name." (".$tcount.")",'taxonomy/term/'
.$term->tid, array('title' => $tcount." posts in "
.$term->name));
if ($children_terms) {
print "
";
print "
";
}
print "
";
}
} /* end foreach */
print "
";
Кто может подсказать как их подружить с pathauto
в меню с снипетом путь один
в реале другой настроен с помощью pathauto
в этом проблема
А как вывести иерархию, чтобы еще выводилась дата последнего обновления верхних терминов (самых родительских)? Т.е. даже если в самом термине материал не добавлялся, но был добавлен в его сыне или внуке, то это бы фиксировалось возле главного родительского термина.
В начале преведен снипет который выводит все термины словаря деревом с колличеством материалов, а вот такая штука:
$tree = taxonomy_get_tree(2, arg(2));
foreach ($tree as $term) {
echo $term->name . '
';
}
Выводит все подподтермины текущего термина..., но они выводятся просто текстом (не ссылки). Я в танке, подскажите пожалуйста, как сделать чтоб они выводились ссылками и деревом с колличеством материалов?
Ничего не понимаю... Drupal 7.2 ругается на неизвестность функции
<?phptaxonomy_term_count_nodes($term->tid);?>
Полазил по api.drupal.org - понял, что некоторые функции (в частности taxonomy_term_count_nodes) не включены в D7. Может кто-то пробовал реализовать такой вот "рубрикатор" уже на новой платформе?
Спасибо!
Если изменить так код, можно управлять выводом пустых терминов
$empty = true; //Показывать пустые категории
$pole = array();
$items = array();
$terms = taxonomy_get_tree($vid);
foreach ( $terms as $term ) {
$count = taxonomy_term_count_nodes($term->tid);
if ($count != 0 || $empty)
$pole[]=Array ((($count) ? l($term->name, "taxonomy/term/$term->tid")." (".$count.")" :'<span class="empty">'.$term->name."(0)".'</span>'), $term->depth, $count, $term->tid,);
}
//............
Замена для семерки функции taxonomy_term_count_nodes
<?php
function d7_taxonomy_term_count_nodes($tid){
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_index', 'i', 'i.tid = t.tid');
$query->addField('i', 'nid');
$query->condition('t.tid', $tid);
$query->addTag('node_access');
$tids = $query->execute()->fetchCol();
return count($tids);
}?>
А можно привести полный код для 7-ки
Код, из каммента выше, у меня ничего не выводит
вот держи:
<?php function d7_taxonomy_term_count_nodes($tid){
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_index', 'i', 'i.tid = t.tid');
$query->addField('i', 'nid');
$query->condition('t.tid', $tid);
$query->addTag('node_access');
$tids = $query->execute()->fetchCol();
return count($tids);
} $vid = 31; /* <---- put correct vocabulary ID here */
$terms = taxonomy_get_tree($vid);
print "<ul>";
foreach ( $terms as $term ) {
$tcount = d7_taxonomy_term_count_nodes($term->tid);
$children_terms = taxonomy_get_children($term->tid);
if ($term->depth == 0) {
print "<li>";
print l($term->name." (".$tcount.")",'taxonomy/term/'
.$term->tid, array('title' => $tcount." posts in "
.$term->name));
if ($children_terms) {
print "<ul>";
foreach ( $children_terms as $children_term ) {
$t_children_count =
d7_taxonomy_term_count_nodes($children_term->tid);
print "<li>";
print l($children_term->name." (".$t_children_count.")",
'taxonomy/term/'.$children_term->tid, array('title' =>
$t_children_count." posts in ".$children_term->name));
print "</li>";
}/* end foreach children */
print "</ul>";
}
print "</li>";
}
} /* end foreach */
print "</ul>";
?>
спасибо, буду пробовать
А можно выводить не все термины 2-го уровня (children) а к примеру штук 10 и сделать ссылку еще... В последнем коде, для 7-ки?
Вот, только без счетчика нод у терминов
<?php
$vid = 3; // id словаря
$cols = 2; // кол-во столбцов для отображения
$limit = 5; // кол-во выводимых дочерних терминов $tree = taxonomy_get_tree($vid, 0, 1);
if (!empty($tree)) {
$output = '<table class="catalog-root">';
$count = 0;
$total = count($tree);
foreach ($tree as $tid => $term) {
if ($count % $cols == 0) {
$output .= '<tr>';
}
$item = '<h3>'. l($term->name, 'taxonomy/term/' . $term->tid) .'</h3>';
$children_list = array();
$children = taxonomy_get_children($term->tid, $vid);
$i = 1;
foreach (taxonomy_get_children($term->tid, $vid) as $child) {
$children_list[] = l($child->name, 'taxonomy/term/' . $child->tid);
if ($limit != 0 && $i >= $limit) break;
$i++;
}
if (count($children) > $limit) {
$children_list[] = l('...', 'taxonomy/term/' . $term->tid);
}
$count++;
$item .= implode(' / ', $children_list);
$output .= '<td>'. $item .'</td>';
if ($count % $cols == 0 || $count == $total) {
$output .= '</tr>';
}
}
$output .= '</table>';
return $output;
}
?>
Неужели никто не знает?
Класс, только бы еще и счетчик
Вывод под 7 со счётчиком.
<?php
$vid = 3; // id словаря
$cols = 2; // кол-во столбцов для отображения
$limit = 5; // кол-во выводимых дочерних терминов function d7_taxonomy_term_count_nodes($tid){
$query = db_select('taxonomy_term_data', 't');
$query->join('taxonomy_index', 'i', 'i.tid = t.tid');
$query->addField('i', 'nid');
$query->condition('t.tid', $tid);
$query->addTag('node_access');
$tids = $query->execute()->fetchCol();
return count($tids);
} $tree = taxonomy_get_tree($vid, 0, 1);
if (!empty($tree)) {
$output = '<table class="catalog-root">';
$count = 0;
$total = count($tree);
foreach ($tree as $tid => $term) {
if ($count % $cols == 0) {
$output .= '<tr>';
}
$item_count = d7_taxonomy_term_count_nodes($term->tid);
$item = '<h3>'. l($term->name." (".$item_count.")", 'taxonomy/term/' . $term->tid) .'</h3>';
$children_list = array();
$children = taxonomy_get_children($term->tid, $vid);
$i = 1;
foreach (taxonomy_get_children($term->tid, $vid) as $child) {
$children_count = d7_taxonomy_term_count_nodes($child->tid);
$children_list[] = l($child->name." (".$children_count.")", 'taxonomy/term/' . $child->tid);
if ($limit != 0 && $i >= $limit) break;
$i++;
}
if (count($children) > $limit) {
$children_list[] = l('...', 'taxonomy/term/' . $term->tid);
}
$count++;
$item .= implode(' / ', $children_list);
$output .= '<td>'. $item .'</td>';
if ($count % $cols == 0 || $count == $total) {
$output .= '</tr>';
}
}
$output .= '</table>';
return $output;
}
?>
А можно прикрутить еще и типы материалов (нод)?
а куда это все вставлять?
В блок, где разрешён PHP.
Очень прошу вашей помощи. У меня с помощью сниппета выведены иерархически термины словаря. Но в русской версии мне надо сделать вывод локализованных терминов. Как это можно сделать?
Код вывода такой:
<?php
$vid = 2; // Номер словаря
$pole = array();
$items = array();
$terms = taxonomy_get_tree($vid);
//var_dump($terms);
foreach ( $terms as $term ) {
$pole[]=Array (l($term->name, taxonomy_term_path($term)), $term->depth, $term->tid) ;
}
$depth =-1;
foreach ($pole as $list) {
//$depth- глубина предыдущего уровня
//$list[1] - глубина текущего элемента
if ($list[1] == $depth) {
echo "
";
next;
}
while ($list[1] != $depth) {
if ($list[1] > $depth) {
$depth++;
echo "\n
";
next;
}
if ($list[1] < $depth) {
$depth--;
echo "\n
\n
";
}
}
echo "\n
$depth=$list[1];
}
//Закрываем все открытые теги до нулевого уровня:
$depth=0;
while ($list[1] != $depth) {
if ($list[1] > $depth) {
$depth++;
echo "
\n
";
}
}
?>
А как вы их хотите локализовывать?
<?php ...
$pole[]=Array (l(t($term->name), taxonomy_term_path($term)), $term->depth, $term->tid);
...
?>
может так?
Спасибо, PVasili. Но я уже перевела весь сайт на 7 друпал и сделала вывод через taxonomy menu. Но вообще спасибо за подсказку!
С помощью 'views' в 'друпал-6' у словаря со сложной структурой иерархии (когда у разных терминов первого уровня может быть разный уровень вложенности его дочерних терминов) нечто подобное сделать не получилось (с помощью 'views' и модуля 'term_node_count' получилось реализовать только подобную структуру для словаря с глубиной в 1 термин (когда есть раздел и подраздел, и когда у всех родителей есть дочерние термины только на 1 уровень в глубину). Стал искать программное решение. Нашел эту тему.
Спасибо вам, взял за основу ваше решение!
Решил реализовать его с помощью модуля. Вот код модуля (вместе с хуком меню, переопределяющим центральную страницу словаря 'taxonomy/term/all'):
<?php
// $Id$
/**
* @file
* Переопределение центрального меню терминов таксономии.
*/
/**
function termspage_menu_alter(&$items) {* Реализация hook_menu().
*/
$items['taxonomy/term/all'] = array(
'title' => 'Каталог оборудования',
'page callback' => 'termspage_catalog',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
} /**
* Обратный вызов меню.
* Вызывается, когда пользователь переходит на 'taxonomy/term/all'
*/
function termspage_catalog() {
$vid = 1; // идентификатор нужного словаря
$terms = taxonomy_get_tree($vid);
$output = "<ul>";
foreach ($terms as $term) {
$tcount = taxonomy_term_count_nodes($term->tid);
$children_terms = taxonomy_get_children($term->tid);
if ($term->depth == 0) {
$output .= "<li>";
$output .= l($term->name." (".$tcount.")",'taxonomy/term/'
.$term->tid, array('title' => $tcount." posts in "
.$term->name));
if ($children_terms) {
$output .= "<ul>";
foreach ($children_terms as $children_term) {
$t_children_count =
taxonomy_term_count_nodes($children_term->tid);
$output .= "<li>";
$output .= l($children_term->name." (".$t_children_count.")",
'taxonomy/term/'.$children_term->tid, array('title' =>
$t_children_count." posts in ".$children_term->name));
$output .= "</li>";
} // end foreach children
$output .= "</ul>";
}
$output .= "</li>";
}
} // end foreach
$output .= "</ul>";
return $output;
}
?>
Не знаю жива ли ветка спустя 14 лет, но если найдется специалист по Drupal 6 который готов выполнить похожую задачу из этого топика за разумные деньги, то напишите пожалуйста в телеграм https://t.me/dmitriy_sadchenko
========Задача=======
Задача в том чтобы в уже готовых раскрытых фильтрах по таксономии на Views отображались только те опции, по которым можно отфильтровать товары на странице категории. То есть по факту чтоб опции в которых нет товаров, не отображались, либо полностью скрывался весь фильтр по словарю, если ни в одной из его опций нет товаров. Самая большая проблема в том, что магазину миллион лет и он до сих пор на Drupal 6. Клиент пока увы не решается на переход на 9-ку, так как это типа убъет органику. В общем если есть кто готов выполнить заказ, напишите в телеграм за какую цену готовы реализовать. Благодарю.