По созданию тем для друпала в интернете можно найти несколько статей (хорошая статья, советую почитать), однако обычно всё заканчивается банальным набором шаблонов и инфо-файлом. В этом топике я постараюсь доступно рассказать как создать гибкую и не самую простую тему.
Начало
Для начала нам потребуется создать директорию в каталоге sites/all/themes с названием нашей темы. Я назвал тему mytheme и создал каталог sites/all/themes/mytheme.
В созданном каталоге создаем директории css — для стилей, js — для скриптов, images — для картинок, templates — для шаблонов, preprocess — об этом позже. Также создаем файл template.php в котором мы будем писать всю логику темы и mytheme.info для описания темы. Можно еще добавить favicon.ico и logo.png.
mytheme.info
Файл содержит всю информацию, необходимую ядру для работы с темой.
Создадим файл примерно со следующим содержанием:
Copy Source | Copy HTML
- ; Название темы, как оно будет отображаться в админке
- name = MyTheme
- ; Описание темы
- description = Моя новая тема
- ; Версия ядра
- core = 6.x
- ; Шаблонизатор используемый темой, по умолчанию phptemplate
- engine = phptemplate
- ; Версия темы
- version = 6.x-1.01
-
- ; Путь к скриншоту темы
- screenshot = images/screenshot.png
-
- ; Регионы темы, в которые можно будет вставлять блоки
- regions[sidebar_right] = Right sidebar
- regions[sidebar_left] = Left sidebar
- regions[header_line] = Line in header
- regions[footer_line] = Line in footer
- regions[content_top] = Content top
- regions[content_bottom] = Content bottom
- regions[content_right] = Content right
- regions[comments_rigth] = Comments right
- regions[page_bottom] = Page bottom
-
- ; Настройки темы, которые будут доступны из админки
- ;features[] = name
- features[] = node_user_picture
- features[] = comment_user_picture
- features[] = search
- ;features[] = favicon
- ;features[] = primary_links
- ;features[] = secondary_links
-
- ; Стили
- stylesheets[all][] = css/blocks.css
- stylesheets[all][] = css/comments.css
- stylesheets[all][] = css/fields.css
- stylesheets[all][] = css/forms.css
- stylesheets[all][] = css/html-reset.css
- stylesheets[all][] = css/layout.css
- stylesheets[all][] = css/messages.css
- stylesheets[all][] = css/navigation.css
- stylesheets[all][] = css/nodes.css
- stylesheets[all][] = css/pages.css
- stylesheets[all][] = css/tabs.css
-
- ;stylesheets[print][] = css/print.css
-
- ;stylesheets[handheld][] = css/mobile.css
- ;stylesheets[only screen and (max-device-width: 480px)][] = css/iphone.css
-
- ; Скрипты
- ;scripts[] = js/script.js
Этого достаточно, чтобы друпал увидел и опознал нашу тему. Я выбрал такой набор стилей и регионов, т.к. нахожу его удобным. Вы можете изменить на свой вкус.
template.php
Самая вкусная часть темы. В этом файле мы будем писать всю логику — хуки.
Для начала определим HOOK_theme().
Copy Source | Copy HTML
- function mytheme_theme(&$existing, $type, $theme, $path) {
- // Определяем базовую тему, если наша тема дочерняя
- static $base_themes = array();
- $base_themes[] = $theme;
-
- // Добавляем хук "process", который будет вызываться после "preprocess".
- if ($type == 'theme') {
- foreach (array_keys($existing) as $hook) {
- if (function_exists($theme . '_preprocess')) {
- $existing[$hook]['preprocess functions'][] = $theme . '_preprocess';
- }
- if (function_exists($theme . '_preprocess_' . $hook)) {
- $existing[$hook]['preprocess functions'][] = $theme . '_preprocess_' . $hook;
- }
- foreach ($base_themes as $base_theme) {
- if (function_exists($base_theme . '_process')) {
- $existing[$hook]['preprocess functions'][] = $base_theme . '_process';
- }
- if (function_exists($base_theme . '_process_' . $hook)) {
- $existing[$hook]['preprocess functions'][] = $base_theme . '_process_' . $hook;
- }
- }
- }
- }
-
- // Добавляем препроцессы только для данной темы, они не распространятся на дочерние темы
- if ($theme == 'mytheme') {
- return array(
- // Добавляем регион. Это необходимо, чтобы мы могли использовать шаблоны для регионов
- 'region' => array(
- // Аргументы, которые будут доступны
- 'arguments' => array('elements' => NULL),
- // Путь к шаблону
- 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
- // Название шаблона. Полное имя файла будет region.tpl.php
- 'template' => 'region',
- // Функции, которые будут подготавливать переменные для шаблонизации
- 'preprocess functions' => array(
- 'template_preprocess',
- 'mytheme_preprocess',
- 'mytheme_preprocess_region',
- 'mytheme_process',
- ),
- ),
- // Выносим header и footer в отдельные шаблоны
- 'header' => array(
- 'arguments' => array('elements' => NULL),
- 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
- 'template' => 'header',
- 'preprocess functions' => array(
- 'template_preprocess',
- 'mytheme_preprocess',
- 'mytheme_preprocess_header',
- 'mytheme_process',
- ),
- ),
- 'footer' => array(
- 'arguments' => array('elements' => NULL),
- 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
- 'template' => 'footer',
- 'preprocess functions' => array(
- 'template_preprocess',
- 'mytheme_preprocess',
- 'mytheme_preprocess_footer',
- 'mytheme_process',
- ),
- ),
- );
- }
- return array();
- }
Определим theme_blocks($region). Функция возвращает набор блоков, доступных для текущего пользователя в заданном регионе.
Copy Source | Copy HTML
- function mytheme_blocks($region) {
- if ($region) {
- $output = '';
-
- if ($list = block_list($region)) {
- foreach ($list as $key => $block) {
- $output .= theme('block', $block);
- }
- }
-
- // Контент для данного региона
- $output .= drupal_get_content($region);
-
- $elements['#children'] = $output;
- $elements['#region'] = $region;
-
- // Возвращаем темизированный регион с блоками. Используется region.tpl.php
- return $output ? theme('region', $elements) : '';
- }
- }
Определим template_preprocess(&$variables, $hook). Функция подготавливает переменные, которые будут переданы в шаблон.
Copy Source | Copy HTML
- function mytheme_preprocess(&$vars, $hook) {
- $key = ($hook == 'page' || $hook == 'maintenance_page') ? 'body_classes' : 'classes';
-
- if (array_key_exists($key, $vars)) {
- if (is_string($vars[$key])) {
- $vars['classes_array'] = explode(' ', $vars[$key]);
- unset($vars[$key]);
- }
- }
- else {
- $vars['classes_array'] = array($hook);
- }
-
- // Тут немного магии.
- // Для каждого хука типа hook_preprocess_anything() мы ищем соответствующий файл
- // в каталоге preprocess и вызываем его
- $name = 'preprocess/preprocess-'. str_replace('_', '-', $hook) .'.inc';
- if (is_file(drupal_get_path('theme', 'mytheme') . '/' . $name)) {
- include($name);
- }
- }
Определим HOOK_process() описанный ранее.
Copy Source | Copy HTML
- function mytheme_process(&$vars, $hook) {
- if (array_key_exists('classes_array', $vars)) {
- // Сливаем в строку все стили для элемента
- $vars['classes'] = implode(' ', $vars['classes_array']);
- }
- }
-
Определим функцию, которая вернет путь к нашей теме.
Copy Source | Copy HTML
- function _mytheme_path() {
- static $path = FALSE;
- if (!$path) {
- $matches = drupal_system_listing('mytheme\.info$', 'themes', 'name', 0);
- if (!empty($matches['mytheme']->filename)) {
- $path = dirname($matches['mytheme']->filename);
- }
- }
- return $path;
- }
-
Ну и наконец, добавим пару функций для обработки классов и id для страниц
Copy Source | Copy HTML
- if (!function_exists('drupal_html_class')) {
- function drupal_html_class($class) {
- $class = strtr(drupal_strtolower($class), array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => ''));
-
- $class = preg_replace('/[^\x{002D}\x{0030}-\x{0039}\x{0041}-\x{005A}\x{005F}\x{0061}-\x{007A}\x{00A1}-\x{FFFF}]/u', '', $class);
-
- return $class;
- }
- }
-
- if (!function_exists('drupal_html_id')) {
- function drupal_html_id($id) {
- $id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
- $id = preg_replace('/[^A-Za-z0-9\-_]/', '', $id);
- return $id;
- }
- }
Часть 2, Часть 3