УрокБыстрый старт в темизации Drupal

7 мая в Беларуси прошёл Drupal Camp Belarus 2011, где я читал доклад по темизации. Хочу поделиться тем, что я рассказывал народу :)

Краткое введение

Тема сайта – это лицо сайта. Пользователю достаточно нескольких секунд чтобы оценить сайт, понять, нравится он ему или нет. Безусловно, каждый сайт выделяется в первую очередь своим функционалом – сайт никогда не получит большую популярность, имея невероятно красивый дизайн, но бесполезный по своей сути. Однако речь пойдёт именно о темизации, о создании красивого и удобного сайта для пользователя.

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

Немного ликбеза

Все темы Друпала, за исключением тех, которые идут в стандартной сборке, должны храниться в папке /sites/all/themes. Сама тема состоит из:

  • Файла, в котором описывается тема, версия ядра, подключаемые стили и скрипты и прочее: имя-темы.info
  • Файлов стандартных шаблонов вывода содержимого: имя-шаблона.tpl.php
  • Файла программной обработки темы: template.php
  • Файлов со стилями: имя-файла.css
  • Файлов с javascript’ами: имя-файла.js
  • Изображения (логотип, скриншот темы, изображения для стилизации)

Единственное, без чего не может существовать тема – это первый пункт списка. Всё остальное по желанию и возможностям.
Подробнее я хочу остановиться именно на втором и третьем пункте списка – а именно на файлах вывода содержимого и файле программной обработки темы, т.к. именно они подготавливают содержимое к выводу.

Вывод содержимого через файлы .tpl.php

В эти файлы из модулей передаётся набор переменных, определённых разработчиком, содержащих контент для вывода.
В Друпале существует набор стандартных файлов шаблонов .tpl.php, которые желательно иметь у себя в теме для свободного изменения внешнего вида. По умолчанию они все лежат в системных модулях, и содержимое выводится именно через них. Однако стоит положить эти файлы к себе в тему и очистить кэш – как содержимое будет выводиться уже через шаблоны внутри темы. Их можно менять внутри, дописывать или удалять свои строки – всё это и есть неотъемлемая часть темизации. Отсюда очевидный плюс – мы не трогаем содержимое модулей, для изменения вывода их содержимого. То есть модули можно обновлять, не опасаясь за возможные проблемы с внешним видом сайта.

Вот список файлов шаблонов, наиболее часто встречающихся в темах:

  • page.tpl.php – сюда передаются переменные с содержимым страницы. Здесь можно найти подключение скриптов, стилей, вывод заголовка страницы, его содержимого, системных сообщений и прочих элементов страницы.
  • maintenance-page.tpl.php – шаблон, отвечающий за вывод страницы сайта, когда он стоит режиме техобслуживания. Передаются те же переменные, что и в page.tpl.php
  • node.tpl.php – сюда передаётся вся информация о выводимом материале – заголовок, содержимое, автор, его таксономия и прочее
  • block.tpl.php – находится информация о выводом блоке – заголовок, содержимое, модуль, которым он был создан (если создан не руками), и т.д.
  • comment.tpl.php – передаются переменные с содержимым выводимого комментария – заголовок, содержимое, автор, и пр.
  • Остальные файлы уже добавляются при необходимости, и берутся они, как я уже говорил, из папки с модулем, вывод которого необходимо переопределить.

Пример работы с файлом node.tpl.php

Содержимое этого файла по умолчанию:

<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?>
  <?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
 
  <?php print $picture ?>
 
  <?php if (!$page): ?>
    <h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
  <?php endif; ?>
 
  <div class="meta">
  <?php if ($submitted): ?>
    <span class="submitted"><?php print $submitted ?></span>
  <?php endif; ?>
 
  <?php if ($terms): ?>
    <div class="terms terms-inline"><?php print $terms ?></div>
  <?php endif;?>
  </div>
 
  <div class="content">
    <?php print $content ?>
  </div>
 
  <?php print $links; ?>
</div>

Вот так выглядит вывод содержимого через этот файл:
1.png
На картинке обычный текст - т.к. заголовок в полной версии материала не выводится (по умолчанию), ссылок и таксономии тут тоже нет.

А теперь скопируем этот файл к себе в тему и немного темизируем его:

<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?>
  <?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
 
  <div class = "created-by">
    <?php print 
      $variables['created_by'] =  
        t('This @type was created by !author at %date', array(
          '@type' => $node->type, 
          '!author' => $name, 
          '%date' => date('d.m.Y H:i', $node->created)
        )); 
    ?>
  </div>
 
  <?php print $picture ?>
 
  <?php if (!$page): ?>
    <h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
  <?php endif; ?>
 
  <div class="meta">
  <?php if ($submitted): ?>
    <span class="submitted"><?php print $submitted ?></span>
  <?php endif; ?>
 
  <?php if ($terms): ?>
    <div class="terms terms-inline"><?php print $terms ?></div>
  <?php endif;?>
  </div>
 
  <div class="content">
    <?php print $content ?>
  </div>
 
  <?php print $links; ?>
</div>

Теперь перед началом статьи располагается надпись о том, кем и когда был создан этот тип материала:

1_0.png

Темизировать шаблоны вывода содержимого можно как используя стандартные переменные, которые передаются в эти шаблоны, так и создавая свои шаблоны. Стандартные переменные, которые передаются в эти шаблоны абсолютно не засекречены, и найти их можно либо в самом файле на английском языке (если брать из модуля) либо вот тут, но на русском: http://drupalace.ru/uroki, либо просто поискать на просторах веба.

Теперь о том, как в шаблоны вывода эти файлы попадают.

Функции предварительной обработки переменных

В Друпале существуют функции, позволяющие централизовано собрать все необходимые данные для передачи их в файлы шаблонов. Что более важно – их можно перекрывать в своей теме, а именно в файле template.php, где должен храниться весь код темы.

Название таких функций выглядят следующим образом: template_preprocess_ключ. Здесь ключ выбирается не случайным образом. Он должен совпадать с ключом массива, возвращаемое в модуле через hook_theme, но это не предметом моей статьи, поэтому я на этом не буду заострять внимания. Главное запомнить эти названия для основных шаблонов вывода материалов. А сделать это нетрудно, т.к. они совпадают с названием самих шаблонов:

  • template_preprocess_page
  • template_preprocess_node
  • template_preprocess_block
  • template_preprocess_comment

В качестве параметра функции передаётся массив с переменными, которые можно использовать как в функции предобработки, так и в самом шаблоне вывода содержимого. Хочу заметить, что эти функции являются абсолютно необязательными в модуле – если их не будет, переменные из нужных функций всё равно дойдут до файлов шаблона вывода. Однако, скорее всего, нам придётся писать код прямо в шаблоне, чтобы их обработать нужным образом и вывести. А большое количество кода в файле шаблона смотрится ну очень некрасиво, да и неправильно это с точки зрения Друпала.

Так вот, чтобы перекрыть функцию предварительной обработки переменных у себя в теме необходимо слово template в названии функции заменить на имя темы. Например, для темы garland функция будет выглядеть так:

function garland_preprocess_page(&$variables) {
  // Some code
}

Как я уже говорил, в этой функции можно создавать и свои переменные для передачи их в шаблон. А так же, я говорил что лишний код в шаблонах – это плохо. Сейчас я объединю эти два утверждения и исправлю то, что сделал немного выше. А именно – уберу темизированную часть из node.tpl.php и положу его в функцию предварительной обработки материала в template.php, затем создам дополнительную переменную, и верну её обратно в node.tpl.php. Вот как это выглядит на практике (работа ведётся в теме garland):
*функция добавлена в template.php*

/**
 * Override or insert node variables into the node.tpl.php
 */
function garland_preprocess_node(&$variables) {
  $variables['created_by'] =  
    t('This @type was created by !author at %date', array(
      '@type' => $variables['node']->type, 
      '!author' => $variables['name'], 
      '%date' => date('d.m.Y H:i', $variables['node']->created)
    )); 
}

Содержимое node.tpl.php:

<div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?>
  <?php if (!$status) { print ' node-unpublished'; } ?> clear-block">
 
  <div class = "created-by">
    <?php print $created_by; ?>
  </div>
 
  <?php print $picture ?>
 
  <?php if (!$page): ?>
    <h2><a href="<?php print $node_url ?>" title="<?php print $title ?>"><?php print $title ?></a></h2>
  <?php endif; ?>
 
  <div class="meta">
  <?php if ($submitted): ?>
    <span class="submitted"><?php print $submitted ?></span>
  <?php endif; ?>
 
  <?php if ($terms): ?>
    <div class="terms terms-inline"><?php print $terms ?></div>
  <?php endif;?>
  </div>
 
  <div class="content">
    <?php print $content ?>
  </div>
 
  <?php print $links; ?>
</div>

Результат остался неизменным:

1_0.png

Отдельно хочу отметить важность работы с функциями предварительной обработки переменных из-за следующей переменной: $variables[‘template_files’]. Она хранит в себе возможные шаблоны перекрытия шаблона вывода, уточнив его каким-либо параметром. Поясню на примере. В стандартной функции предобработки переменных для страницы имеет место быть следующий код:

  $i = 0;
  $suggestion = 'page';
  $suggestions = array();
  while ($arg = arg($i++)) {
    $arg = str_replace(array("/", "\\", "\0"), '', $arg);
    $suggestions[] = $suggestion .'-'. $arg;
    if (!is_numeric($arg)) {
      $suggestion .= '-'. $arg;
    }
  }
  if (drupal_is_front_page()) {
    $suggestions[] = 'page-front';
  }
 
  if ($suggestions) {
    $variables['template_files'] = $suggestions;
  }

Он позволяет создать отдельный шаблон для абсолютно любой страницы. Т.е. я могу создать шаблон page-node-1.tpl.php (скопировав туда всё содержимое page.tpl.php), потом оставить там только вывод заголовка страницы и всунуть, например баннер. Далее пользователь, который зайдёт на страницу /node/1 увидит лишь заголовок страницы и баннер. Все же остальные материалы останутся без изменений. Т.е. в шаблон можно вписать любые аргументы урла из адресной строки – и для этой страницы будет создан собственный шаблон. Например, страницу http://example.ru/node/add/new можно перекрыть шаблоном page-node-add-new.tpl.php. Если нет такого шаблона, то Друпал будет искать шаблон page-node-add.tpl.php, далее page-node.tpl.php, и потом уже вернётся к родному page.tpl.php. Для главной страницы предусмотрен шаблон page-front.tpl.php.

Для материала, например, можно создавать шаблоны по принципу node-номерСтатьи.tpl.php. Т.е. для материала с уникальным идентификатором 232 шаблон будет выглядеть так: node-232.tpl.php.

Более того, Друпал позволяет создавать собственные шаблоны. Главное правильно задать условие работы шаблонов.

Пример: необходимо создать шаблон страницы, который будет отображён в зависимости от типа материала. Решение:

/**
 * implementation of template_preprocess_page()
 */
function ИМЯТЕМЫ_preprocess_page(&$variables)  { 
  if (isset($variables['node']) && $variables['node']->type) {
	$variables['template_files'][] =  'page-node-type-'.$variables['node']->type;
  } 
}

Теперь, например, для типа материала story шаблон выглядит page-node-type-story.tpl.php. Можно зайти в этот шаблон и поменять/добавить/удалить элементы страницы. Данное изменение коснётся только материалы типа story и только при полном просмотре статьи.

Комментарии

Аватар пользователя Евгений
Евгений написал:

Отличная статья , спасибо!

09.05.2011 13:40
Аватар пользователя krak
krak написал:

А так можно сделать?
node-type-story.tpl.php для переопределение вывода данных для типа story? Или надо писать Вашу заглушку в конце статьи?

18.05.2011 17:50
Аватар пользователя Spleshka
Spleshka написал:

не node-type-story.tpl.php, а node-story.tpl.php - это стандартный шаблон, заглушек писать не надо

18.05.2011 21:55
Аватар пользователя krak
krak написал:

Что-то в семерке это не работает.

19.05.2011 10:54
Аватар пользователя Spleshka
Spleshka написал:

Так уточнять надо под какой Drupal ;)
в 7ке это то ли node--story.tpl.php, то ли node__story.tpl.php, попробуй оба варианта

19.05.2011 16:14
Аватар пользователя krak
krak написал:

К сожалению, не удалось связаться с Вами ни по Скайпу, ни по Аське. Имя файла подтянулось (первый вариант). А как узнать какие переменные доступны в этом файле?

20.05.2011 17:13
Аватар пользователя Тайный поклонник
Тайный поклонник написал:

print_r($node);

24.05.2011 13:18
Аватар пользователя Тайный поклонник
Тайный поклонник написал:

не подскажите где можно изучить вопрос темизации для 7-ки только, желательно поподробнее

26.08.2011 03:14
Аватар пользователя Тайный поклонник
Тайный поклонник написал:

спс за статью

02.10.2011 15:21
Аватар пользователя Михаил
Михаил написал:

Подскажите, если не сложно а если захотеть иметь 2 возможности вывода форм.
Ну например по ссылке node/add/page мне нужна стандартная фома, а по ссылке node/add/page/ajax я хочу чтобы клиенту drupal возвращал только тело формы. Как такое реализовать??

16.02.2012 10:25
Аватар пользователя Михаил
Михаил написал:

Ой все поразмыслив понял.
page-node-add-page-ajax.tpl.php
Сам себе и ответил. СПАСИБО ЗА СТАТЬЮ.

16.02.2012 10:52
Аватар пользователя Yorik
Yorik написал:

.....Например, страницу http://example.ru/node/add/new можно перекрыть шаблоном page-node-add-new.tpl.php.

Создал page-node-add-new.tpl.php пустой, даже page-node-add.tpl.php ну никак не могу понять как перекрыть, поясните.

14.06.2012 16:54
Аватар пользователя Spleshka
Spleshka написал:

Если 6й друпал - просто сбросьте кэш и всё подцепится. Если седьмой, то шаблон должен быть page--node--add--new.tpl.php, после чего опять же - сбросьте кэш.

21.06.2012 10:35
Аватар пользователя Yorik
Yorik написал:

Всё на 7-ке. Спасибо сработало, действительно, кэш - моз выносил (чёт с одного раза не скидывается, в производительности все галочки сняты, в браузере Ф5, очищал все кэши но с первого раза не работает ??????... )
Прошу вновь пояснить, у вас на сайте только правый блок, я хочу так же, но только на определённых типах материала, создал page--report.tpl.php (скопировав содержимое простого page.tpl.php) удалил левый блок в шаблоне (с кэшем боролся, как выше писал) - опять нет результата. Разжуйте если можно, у вас это чинно получается :))))

22.07.2012 09:49
Аватар пользователя Stown
Stown написал:

Что-то не получается создать переменную

<?php  
 
function newspaper_preprocess_node(&$variables) {
 
$variables['ima'] = theme('image_style',array(
  'style_name' => 'large',
  'path' => $node->field_image['und']['0']['uri'],
  'alt' => $node->title,
  ));
}
 
?>

В node.tpl.php. вставляю print $ima; и ничего не выводится, а если просто. весть код в файл ноды вставляю, картинка отображается

29.07.2012 07:03
Аватар пользователя Stown
Stown написал:
<?php print $ima; ?>

Естественно вставляю

29.07.2012 07:04
Аватар пользователя Stown
Stown написал:

Нужно было писать так:

function newspaper_preprocess_node(&$variables) {
 
$variables['ima'] = theme('image_style',array(
 'style_name' => 'large',
  'path' => $variables['node']->field_image['und']['0']['uri'],
  'alt' => $variables['node']->title
  )); 
}
29.07.2012 16:24
Аватар пользователя Айрин
Айрин написал:

Столько статей прочла про темизацию и впервые нашла действительно очень полезный материал-сразу видно, что рассказывает профессионал. Спасибо. Действительно интересно

05.04.2013 20:14
Аватар пользователя bigfeurmdron
bigfeurmdron написал:

С позволения автора выложу здесь пдф-ку - структурированный список всех переменных и порядок именования шаблонов в друпал 7. Очень полезная штука. Ссылка на обменник

19.02.2015 14:58

Комментировать