Вопрос «Как вывести термины таксономии с числом нод» мелькает на форумах с завидной регулярностью, то есть вопрос этот — важный. Можно воспользоваться модулем (только Drupal 6), обходным маневром (через контекстные фильтры Views) или включить в том же модуле Views аггрегацию. На последнем способе в этой заметке мы и остановимся подробнее, так как первый — устарел, а второй — не всегда может подойти.
Основная проблема аггрегации Views в том, что она никак не учитывает материалы в дочерних терминах. Вот о том, как это победить, и пойдет речь.
Чтоб далеко не ходить за примером, возьмем разработанный нами каталог Decking-Mall. На главной странице как раз выводится каталог товаров с подсчетом числа позиций внутри категории. У этого каталога ряд особенностей. Во-первых, словарь каталога выводится не с корня (потому что для разных регионов нашей страны выводится свой каталог), поэтому зацепиться за верхний термин будет непросто. Во-вторых, выводятся не все дочерние термины, а только два уровня родитель-дети. И в третьих, подсчитывать число материалов нужно только для дочерних терминов, а для родителей — не надо. В общем, в силу этих особенностей проще было сделать вывод с помощью аггрегации Views. Однако, подсчет материалов в каталоге, тем не менее, происходит с учетом дочерних терминов. Сделать это нетрудно, но нужно написать код.
Допустим, наше представление каталога называется product_categories
. Создадим модуль и добавим в него код с реализацией хука hook_views_pre_render()
.
//хук hook_views_pre_render позволяет поработать с результатами
//представления, когда они уже готовы, но их вывод еще не начался
function mymodule_views_pre_render(&$view) {
//убедимся, что это наше представление
if ($view->name == 'product_categories') {
$tids = array();
foreach ($view->result as $position => $result) {
//сохраним все id терминов, для которых
//нужно уточнить число материалов
$tids[$result->tid] = $position;
}
//найдем id словаря
//у меня он берется из поля taxonomy_term_data_taxonomy_term_hierarchy_1_vid,
//но в вашем представлении поле может (и будет) называться иначе
$voc = $view->result[0]->taxonomy_term_data_taxonomy_term_hierarchy_1_vid;
//загрузим все дерево терминов
$tree = taxonomy_get_tree($voc);
//пробежимся по дереву терминов и сохраним только те из них, у которых есть дочерние.
$tid_chains = array();
foreach ($tree as $index => $term) {
$i = $index+1;
$ctid = array();
$ctid[] = $term->tid;
//пробежимся по дереву вниз, начиная с текущего термина
//(taxonomy_get_tree сортирует термины по родителям)
//будем сохранять цепочки вида термин => array(его дети)
$children = array();
while ($i < count($tree)) {
//заметим, что использование parents[0] не позволит
//работать с несколькими родителями одного термина
//но нам и не надо
if (!in_array($tree[$i]->parents[0], $ctid)) {
break; //термин не дочерний для цепочки
}
//сохраним id термина для следующей итерации
//(вдруг для него дочерний есть?)
$ctid[] = $tree[$i]->tid;
//добавим текущий термин в массив дочерних
$children[] = $tree[$i]->tid;
$i ++;
}
//если дети нашлись, сохраним
if (count($children)) {
$tid_chains[$term->tid] = $children;
}
}
//теперь осталось только подсчитать материалы
//для всех детей каждого термина
foreach ($tid_chains as $parent => $children) {
//считаем
$count = _mymodule_count_terms_nodes($children);
//уточняем данные представления на полученную величину
$view->result[$tids[$parent]]->node_taxonomy_index_nid += $count;
}
}
}
function _mymodule_count_terms_nodes($tids) {
//EntityFieldQuery позволяет строить запросы к БД
//для поиска сущностей по значению их свойств и полей.
//Хорошая вещь!
//Гораздо лучше, чем ковыряться в таблицах поля напрямую.
$query = new EntityFieldQuery();
$count = $query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'regional_product')
->propertyCondition('status', 1)
//field_locality - это ссылка на термин таксономии
//именно она связывает материал с каталогом
->fieldCondition('field_locality', 'tid', $tids, 'IN')
->count()
->execute();
return $count;
}
Собственно, вот и все. Нужно, однако, заметить, что если словарь с каталогом — достаточно ветвистый, то не стоит пренебрегать кэшированием Views. Впрочем, им вообще не стоит пренебрегать без веских причин.