

Данная статья повествует о темизации вьюсов пятой версии Друпала. Темизация для шестой ветки будет расписана позже. Оставайтесь с нами ;)
С выходом релиз-кандидатов модулей Views 2 и CCK 2 для шестой версии друпала, стоит уже серьезно задуматься о переходе на Drupal 6.
Чтобы дать толчок этому процессу, я решил окончательно раскрыть тему темизации этих модулей, сначала, для пятой ветки, а затем и для шестой.
Итак, начнем с темизации вьюсов.
Наверное, первым камнем преткновения разработчика, познавшего начальные прелести Друпала, является темизация модуля Views. Этот процесс содержит минимум документации, так что, порой, некоторые начинающие разработчики вообще не догадываются, что с вьюсами можно что-то делать.
В поставку модуля Views входит модуль Views Theme Wizard. Включив этот модуль, вы получите инструмент быстрого создания простых шаблонов темизации вьюсов:

Данный способ предполагает темизацию только вьюсов List-типа. Если у вас табличные, тизеровые или какие-то другие вьюсы — данный подход ничем вам не поможет.
Но не стоит отчаиваться, так как в модуле Views заложена уйма методов темизации. Рассмотрим все варианты.
В модуле можно найти замечательнуй функцию theme_views_view, а немного порыскав в коде, можно еще и найти ее вариации:
// изменения будут затрагивать только вьюсу с названием VIEW_NAME и типом VIEW_TYPE
// function phptemplate_views_view_VIEW_TYPE_VIEW_NAME($view, $type, $nodes, $level = NULL, $args = NULL) { ... }
// изменения будут затрагивать только вьюсу с названием VIEW_NAME, любого типа
// function phptemplate_views_view_VIEW_NAME($view, $type, $nodes, $level = NULL, $args = NULL) { ... }
// изменения будут затрагивать все вьюсы
function phptemplate_views_view($view, $type, $nodes, $level = NULL, $args = NULL) {
$num_nodes = count($nodes);
if ($type == 'page') {
drupal_set_title(filter_xss_admin(views_get_title($view, 'page')));
views_set_breadcrumb($view);
}
if ($num_nodes) {
$output .= views_get_textarea($view, $type, 'header');
}
if ($type != 'block' && $view->exposed_filter) {
$output .= views_theme('views_display_filters', $view);
}
$plugins = _views_get_style_plugins();
$view_type = ($type == 'block') ? $view->block_type : $view->page_type;
if ($num_nodes || $plugins[$view_type]['even_empty']) {
if ($level !== NULL) {
$output .= "<div class='view-summary ". views_css_safe('view-summary-'. $view->name) ."'>". views_theme($plugins[$view_type]['summary_theme'], $view, $type, $level, $nodes, $args) . '</div>';
}
else {
$output .= "<div class='view-content ". views_css_safe('view-content-'. $view->name) ."'>". views_theme($plugins[$view_type]['theme'], $view, $nodes, $type) . '</div>';
}
$output .= views_get_textarea($view, $type, 'footer');
if ($type == 'block' && $view->block_more && $num_nodes >= $view->nodes_per_block) {
$output .= theme('views_more', $view->real_url);
}
}
else {
$output .= views_get_textarea($view, $type, 'empty');
}
if ($view->use_pager) {
$output .= theme('pager', '', $view->pager_limit, $view->use_pager - 1);
}
if ($output) {
$output = "<div class='view ". views_css_safe('view-'. $view->name) ."'>$output</div>\n";
}
return $output;
}
Таким образом, мы получаем очень гибкий способ темизации, приктически любой вьюсы. Рассмотрим примеры.
Этот код очень похож на то, что генерирует модуль Views Theme Wizard, за исключением того, что данный код не пытается подключать внешние шаблоны, как это делает мастер. Если вам все же нужно подключить внешний шаблон, напомню, что это делается функцией _phptemplate_callback().
// вариация с именем вьюсы:
// function phptemplate_views_view_list_VIEW_NAME($view, $nodes, $type) { ... }
function phptemplate_views_view_list($view, $nodes, $type) {
$fields = _views_get_fields();
// составление строк списка
foreach ($nodes as $node) {
$item = '';
foreach ($view->field as $field) {
if (!isset($fields[$field['id']]['visible']) && $fields[$field['id']]['visible'] !== FALSE) {
if ($field['label']) {
$item .= "<div class='view-label ". views_css_safe('view-label-'. $field['queryname']) ."'>" . $field['label'] . "</div>";
}
// темизация отдельного поля
$item .= "<div class='view-field ". views_css_safe('view-data-'. $field['queryname']) ."'>" . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "</div>";
}
}
$items[] = "<div class='view-item ". views_css_safe('view-item-'. $view->name) ."'>$item</div>\n"; // l($node->title, "node/$node->nid");
}
if ($items) {
return theme('item_list', $items);
}
}
// вариация с именем вьюсы:
// function phptemplate_views_view_table_VIEW_NAME($view, $nodes, $type) { ... }
function phptemplate_views_view_table($view, $nodes, $type) {
$fields = _views_get_fields();
// составление строк таблицы
foreach ($nodes as $node) {
$row = array();
foreach ($view->field as $field) {
if ($fields[$field['id']]['visible'] !== FALSE) {
// темизация отдельного поля
$cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view);
$cell['class'] = "view-field ". views_css_safe('view-field-'. $field['queryname']);
$row[] = $cell;
}
}
$rows[] = $row;
}
// вывод таблицы
return theme('table', $view->table_header, $rows);
}
// вариация с именем вьюсы:
// function phptemplate_views_view_teasers_VIEW_NAME($view, $nodes, $type) { ... }
function phptemplate_views_view_teasers($view, $nodes, $type) {
return views_theme('views_view_nodes', $view, $nodes, $type, true);
}
// вариация с именем вьюсы:
// function phptemplate_views_view_nodes_VIEW_NAME($view, $nodes, $type, $teasers = false, $links = true) { ... }
function phptemplate_views_view_nodes($view, $nodes, $type, $teasers = false, $links = true) {
foreach ($nodes as $n) {
$node = node_load($n->nid);
$output .= node_view($node, $teasers, false, $links);
}
return $output;
}
Этот код дает представление о том, как темизировать списки нод, но что если нужно темизировать сами ноды когда они появляются во вьюсах? Все довольно таки просто. В шаблонах node[-node_type].tpl.php нужно вставить такой код:
<?php global $current_view; ?>
<?php if ($current_view->name == 'viewname') { ?> // измените для вашего случая
// здесь вставлять свой код
<?php }; ?>
Думаю, здесь пояснения излишни.
Довольно редко используемое, summary-представление вьюсы, можно использовать, когда в вашей вьюсе используются аргументы. Возьмем к примеру, стандартную вьюсу taxonomy_term. Если в настройках аргумента выбрать в поле "Умолчания" правило "Summary", то при показе этой вьюсы без аргумента, все будет выглядеть примерно так:

Код темизации summary-представления:
// вариация с именем вьюсы:
// function phptemplate_views_summary_VIEW_NAME($view, $type, $level, $nodes, $args) { ... }
function phptemplate_views_summary($view, $type, $level, $nodes, $args) {
foreach ($nodes as $node) {
$items[] = views_get_summary_link($view->argument[$level]['type'], $node, $view->real_url) . " (" . $node->num_nodes . ")";
}
if ($items) {
$output .= theme('item_list', $items);
}
return $output;
}
Темизация отдельных полей вьюшек — еще плотнее завешена покровом тайны, потому что явного вызова этих функций в коде модуля Views нет нигде. Однако, они существуют:
// вариация с именем поля:
// function phptemplate_views_handle_field_FIELD_NAME($fields, $field, $data) { ... }
// вариация с именем вьюсы и поля:
// function phptemplate_views_handle_field_VIEW_NAME_FIELD_NAME($fields, $field, $data) { ... }
function phptemplate_views_handle_field($fields, $field, $data) {
$info = $fields[$field['fullname']];
if ($field['handler'] && function_exists($field['handler'])) {
return $field['handler']($info, $field, $data->$field['queryname'], $data);
}
if ($info['handler'] && is_string($info['handler']) && function_exists($info['handler'])) {
return $info['handler']($info, $field, $data->$field['queryname'], $data);
}
return check_plain($data->$field['queryname']);
}
Примечание: FIELD_NAME это не привычное название поля (типа field_image или field_mytext). Правильное значние FIELD_NAME находится в переменной $field['queryname'], поэтому, чтобы понять как назвать конкретную функцию, назовите ее сначала просто phptemplate_views_handle_field, а затем, в ее начале вставьте команду print_r($field['queryname']). Она и выведет корректное название (названия бывают довольно таки страшные, как node_data_field_image_field_image_fid, но не следует этого боятся, просто вставляйте это в название функции вместо FIELD_NAME).
Все фильтры во вьюсах можно сделать доступными для пользовательского ввода. В этом случае, за темизацию формы фильтра отвечает следующий код:
// вариация с именем вьюсы:
// phptemplate_views_filters_VIEW_NAME($form) { ... }
function phptemplate_views_filters($form) {
$view = $form['view']['#value'];
foreach ($view->exposed_filter as $count => $expose) {
$row[] = drupal_render($form["op$count"]) . drupal_render($form["filter$count"]);
$label[] = $expose['label'];
}
$row[] = drupal_render($form['submit']);
$label[] = '';
return drupal_render($form['q']) . theme('table', $label, array($row)) . drupal_render($form);
}
Не могу не упомянуть о возможности темизировать ссылку "More", которая появляется в блочных вьюсах когда элементов в списке больше, чем может вместить блок:
function phptemplate_views_more($url) {
return "<div class='more-link'>" . l(t('more'), $url) . "</div>";
}
Есть еще одна функция темизации, о которой я не упоминал. Но она используется только в случае программной вставки вьюшки в страницу (например так print(theme('view','current_user_buddys'));), а именно:
function phptemplate_view($view_name, $limit = NULL, $use_pager = NULL, $type = 'embed', $view_args = array()) {
if ($view = views_get_view($view_name)) {
$use_pager = isset($use_pager) ? $use_pager : $view->use_pager;
$limit_default = ($type == 'block') ? $view->nodes_per_block : $view->nodes_per_page;
$limit = isset($limit) ? $limit : $limit_default;
return views_build_view($type, $view, $view_args, $use_pager, $limit);
}
}
22 комментария
# | beerman
А как темизировать поле image в случае табличного представления, чтобы в таблицу не пихались все картинки этого поля, а только, к примеру, первая?
# | neochief
Полагаю, через
phptemplate_views_handle_field_VIEW_NAME_FIELD_NAME($fields, $field, $data) { ... }В точности код не скажу, надо смотреть по обстановке. Прийдется поиграться с переменной $data
# | Michael
Спасибо. Очень полезная статья.
# | Лера Мулина
Извините за, может быть, слишком простой вопрос:
то есть эти изменения надо вписать в views.module, чтобы иметь возможность темизировать views через css? А если их не прописать, то изменения во views через css нельзя делать?
Я правильно поняла?
# | neochief
Эти функции добавляются в template.php файл вашей темы. Ними можно поменять вывод в html, потому что бывает так, что нужное попросту не размечено CSS классами.
# | Лера Мулина
то есть если прописать эти функции, то для этих элементов появляются классы?
# | beerman
темизация ССК имеет функцию
function phptemplate_field_node_data_field_FIELDNAME_fid(&$node, &$field, &$items, $teaser, $page) {
...
return _phptemplate_callback('field', $variables, array('field-'. $field['field_name']));
}
при вставке кода print $field['field_name']; перед возвратом, получаю имя поля типа node_data_field_FIELDNAME.field_FIELDNAME_fid
т.е., как я понимаю, имя файла темизации должно быть вида field-node_data_field_FIELDNAME.field_FIELDNAME_fid.tpl.php так?
но он не цепляется.
учитель, колитесь ;)
# | beerman
нифига не там я его получал. а функция вызывается только при просмотре ноды... пойду views_handle поковыряю
# | Алексей Королев
Отличный материал, у меня как раз сайт на drupal :) Спасибо!
# | ikent
Супер, все круто написано!
# | KCEOH
Опечатка
назовите ее сначала ghjcnj phptemplate_views_handle_field
Пошел курить на тему табличных вьюсов и творить на своём сайте :)
# | Лера Мулина
А подскажите, пожалуйста, как мне решить следующую задачу: Через
// load the context-node's 'metadata'
global $current_view;
// * define the context-node's NID as the argument
$current_view->args[0]=$node->nid;
// * select the name of the view to embed as $view1
$view1 = views_get_view('imagegallery');
// * define this section for CSS
print '';
// * display a subtitle for the view section
print '' . t($node->title . '') . '';
// send $args to the View's Argument Handler and display $view1 in the context-node
print (views_build_view('embed', $view1, $current_view->args, false, false));
print '';
Я вывела в ноду фильма с табличкой фотографий, относящихся к нему. Но проблема в том, что эта галерея отображается и в полной нода и в тизерной, где она вообще не нужна.
Куда копать вообще в решении этой задачи. Через css могу скрыть. Но скрывается тогда и в ноде и в тизере. Через display fields - избирательно скрыть тоже не могу. Вот такая проблема.
# | Лера Мулина
Решила! Оказывается классы этой галереи были потомками разных классов. И вот с помощью класса и потомка я настроила display: none
# | Mariquit
Здравствуйте.
Возможно ли при выводе тизерной вьюсы добавить классы odd и even?
Можно ли где-то найти пример.
Большое спасибо
# | neochief
# | Mariquit
Спасибо, работает.
В конце только строка
$output .= ''.node_view($node, $teasers, false, $links).'';ато лесенкой теги закрывает.
# | beerman
<?php function theme_views_view_news($view, $type, $nodes) ?>
во views в списке полей значится Node:Body, но при выводе
<?php print_r($nodes) ?>
его нет. подскажите, где его можно получить?
# | beerman
хых...
$node = node_load($nodes[n]->nid);
# | goran
А есть ли наработки по темизации Views2, по сути API там достаточно отличается от первой, а документаций почти нигде нет.
# | Вячеслав
А можно пример пожалуйста. А то немного не пойму:
1. Я создал представление - блок, с именем - views_test_material
2. Поместил код - Темизация любых типов вьюсов в файл темы template.php (добавил в него из Вашей статьи).
3. В Drupal 5 я в папку темы помещал файлы:
а) views-list-views_test_material.tpl.php с кодом:
<?php drupal_add_css(path_to_theme() .'/views-list-views_test_material.css'); ?>
б) views-list-views_test_material.css с кодом:
.view-label {}
.view-field {}
А в Drupal 6 файлы п.3 не работают, что нужно в них и в их имени исправить что бы всё заработало?
# | Максим
<?php
// load the context-node's 'metadata'
global $current_view;
// * define the context-node's NID as the argument
$current_view->args[0]=$node->nid;
// * select the name of the view to embed as $view1
$view1 = views_get_view('refer');
// * define this section for CSS
print '';
// * display a subtitle for the view section
print '' . t($node->title . ' Issues') . '';
// send $args to the View's Argument Handler and display $view1 in the context-node
print (views_build_view('embed', $view1, $current_view->args, false, false));
print '';
?> - работает на пятерке на шестерке не может найти функцию views_build_view как это обойти?
# | Mariquit
Можно ли темизировать саму страницу вывода вьюсы?
Т.е. тип вьюсы - Page, а как для этой page задать шаблон отличающийся от page.tpl.php?
Оставить комментарий