Темизация не стандартными методами в Друпал

Работая над небольшим проектом, столкнулся с проблемой – если какой-либо модуль не предоставляет хуков по темизации вывода своего контента, то довольно сложно темизировать представить информацию в нужном виде. Но как всегда – Друпал гибок и могуч, и эту проблему можно обойти если модуль использует (и регистрирует) свои функции темизации в общем реестре.

Опишу суть проблемы. В моем проекте использовался свой тип материала (определенный соответствующим модулем), который (тип материала) посредством этого модуля выводился в две колонки (при этом был переопределен вывод ноды, что в общем то не важно) . Но кроме этого в данном типе материала использовались несколько словарей, определяющих некоторые специфичные свойства данного типа материала. Термины данных словарей выводились в ноде в виде активных ссылок при клике на которых должны выводиться ноды с соответствующим признаком. Вся проблема заключалась в том, что вывод должен осуществляться в точно в том же виде как и основной вывод предоставляемый модулем (т.е. в нашем случае в две колонки) и при этом модуль taxonomy не предоставляет интерфейса по переопределению вывода, но при этом имеет зарегистрированную функцию темизации taxonomy_term_page.

Решение данной проблемы возможно за счет подмены функции темизации в глобальном регистре тем Друпала. В этом нам поможет хук
hook_theme_registry_alter(&$theme_registry) , который позволяет переопределить любую зарегистрированную функцию темизации на свою (кстати не только функцию непосредственно темизации, но и preprocess функции и еще много чего интересного, советую посмотреть, что содержится в переменной $theme_registry).

Ну что же перейдем к конкретике.
Модуль который определяет новый тип материала и его вывод называется условно loross (это, что бы в дальнейшем не ссылаться на то, что фрагмент hook в названии функции надо заменять на наименование своего модуля).
В первую очередь определим функцию псевдо-темизации, которая заменит нам стандартную функцию вывода модуля taxonomy (theme_taxonomy_term_page).

Определим хук в нашем модуле который переназначит нужную нам функцию темизации

function loross_theme_registry_alter(&$theme_registry) {
 // переназначим вывод для таксономии
  $theme_registry['taxonomy_term_page']['function'] = 'theme_taxonomy_loross_term_page';
}

// lmodel – это тип материала определенный в модуле
define ('LMODEL_NODE_TYPE', 'lmodel');

function theme_taxonomy_loross_term_page($tids, $result) {
// нам надо определить входит ли данный термин в словарь прикрепленный
// к данному типу материала
  $is_replace_theme = true;
// получаем список словарей для данного типа материала
  $voc = taxonomy_get_vocabularies(LMODEL_NODE_TYPE);
  $voc_vid = array();
// и сохраняем их в массиве
  if ($voc && is_array($voc)) {
        foreach($voc as $key => $value){
        $voc_vid[] = $value->vid;
        }
  }

// проверяем принадлежит ли термин словарю включенному в тип материала
  foreach($tids as $key => $tid){
        $t = taxonomy_get_term($tid);
    if(!in_array($t->vid,$voc_vid)) {
                $is_replace_theme = false;
                break;
        }
  }
//  если нет, то используем стандартную функцию модуля taxonomy
  if(!$is_replace_theme) {
        $output = theme_taxonomy_term_page($tids, $result);
  }
  else {
// если это наш случай, то начинаем определять свой вывод в виде таблицы мз двух столбцов
    $output ='';
    $rows = array();
    $i = 1;
    $row=array();
    while ($node = db_fetch_object($result)) {
      $n = node_load($node->nid);
      $class = (($i % 2) == 0)?'lmodel-item right': 'lmodel-item left';
      $row[] =array('data'=>theme('lmodel',$n),'class'=>$class);
      if (($i % 2)==0)  {
        $rows[]=$row;
        $row=array();
      }
           $i++;
    }
// здесь мы отдельно обрабатываем случай, когда в выборку попала только одна нода
   if(!count($rows) && count($row)) {
        $rows[] = $row;
   }

   $attributes = array('class' => "lmodel-view");
   if (count($rows)) {
// Здесь формируем стандартный табличный вывод
   $pager = theme('pager', NULL, variable_get('default_nodes_main', 10));
// и листалку
   $output .= theme('table', NULL, $rows, $attributes);
   }
   $output .= $pager;
   }
  return $output;
}

Вот и все, теперь после сброса кэша регистра тем, вместо стандартного вывода материалов нашего типа для прикрепленных терминов будет использован вывод определенный в нашей функции (при этом нашу функцию даже не надо регистрировать в регистре тем (см. hook_theme), так как она подменяет уже зарегистрированную там функцию темизации.

Посмотреть как это выглядит в реале, можно на сайте www.loross.ru – весь вывод с облака тэгов и терминов внутри нод организован через подмену функции темизации (при этом не модули cck ни модуль views – не используется) .


PS. Да сайт пока в разработке, так что критика в адрес контента и дизайна принимается но со скидкой на недоделанность ;)