Pull to refresh

Создаём тему для Drupal 6. Часть 1

Reading time 11 min
Views 29K
image
По созданию тем для друпала в интернете можно найти несколько статей (хорошая статья, советую почитать), однако обычно всё заканчивается банальным набором шаблонов и инфо-файлом. В этом топике я постараюсь доступно рассказать как создать гибкую и не самую простую тему.

Начало


Для начала нам потребуется создать директорию в каталоге 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
  1. ; Название темы, как оно будет отображаться в админке
  2. name = MyTheme
  3. ; Описание темы
  4. description = Моя новая тема
  5. ; Версия ядра
  6. core = 6.x
  7. ; Шаблонизатор используемый темой, по умолчанию phptemplate
  8. engine = phptemplate
  9. ; Версия темы
  10. version = 6.x-1.01
  11.  
  12. ; Путь к скриншоту темы
  13. screenshot = images/screenshot.png
  14.  
  15. ; Регионы темы, в которые можно будет вставлять блоки
  16. regions[sidebar_right] = Right sidebar
  17. regions[sidebar_left] = Left sidebar
  18. regions[header_line] = Line in header
  19. regions[footer_line] = Line in footer
  20. regions[content_top] = Content top
  21. regions[content_bottom] = Content bottom
  22. regions[content_right] = Content right
  23. regions[comments_rigth] = Comments right
  24. regions[page_bottom] = Page bottom
  25.  
  26. ; Настройки темы, которые будут доступны из админки
  27. ;features[] = name
  28. features[] = node_user_picture
  29. features[] = comment_user_picture
  30. features[] = search
  31. ;features[] = favicon
  32. ;features[] = primary_links
  33. ;features[] = secondary_links
  34.  
  35. ; Стили
  36. stylesheets[all][] = css/blocks.css
  37. stylesheets[all][] = css/comments.css
  38. stylesheets[all][] = css/fields.css
  39. stylesheets[all][] = css/forms.css
  40. stylesheets[all][] = css/html-reset.css
  41. stylesheets[all][] = css/layout.css
  42. stylesheets[all][] = css/messages.css
  43. stylesheets[all][] = css/navigation.css
  44. stylesheets[all][] = css/nodes.css
  45. stylesheets[all][] = css/pages.css
  46. stylesheets[all][] = css/tabs.css
  47.  
  48. ;stylesheets[print][] = css/print.css
  49.  
  50. ;stylesheets[handheld][] = css/mobile.css
  51. ;stylesheets[only screen and (max-device-width: 480px)][] = css/iphone.css
  52.  
  53. ; Скрипты
  54. ;scripts[] = js/script.js


Этого достаточно, чтобы друпал увидел и опознал нашу тему. Я выбрал такой набор стилей и регионов, т.к. нахожу его удобным. Вы можете изменить на свой вкус.

template.php


Самая вкусная часть темы. В этом файле мы будем писать всю логику — хуки.

Для начала определим HOOK_theme().
Copy Source | Copy HTML
  1. function mytheme_theme(&$existing, $type, $theme, $path) {
  2.     // Определяем базовую тему, если наша тема дочерняя
  3.     static $base_themes = array();
  4.     $base_themes[] = $theme;
  5.  
  6.     // Добавляем хук "process", который будет вызываться после "preprocess".
  7.     if ($type == 'theme') {
  8.         foreach (array_keys($existing) as $hook) {
  9.             if (function_exists($theme . '_preprocess')) {
  10.                 $existing[$hook]['preprocess functions'][] = $theme . '_preprocess';
  11.             }
  12.             if (function_exists($theme . '_preprocess_' . $hook)) {
  13.                 $existing[$hook]['preprocess functions'][] = $theme . '_preprocess_' . $hook;
  14.             }
  15.             foreach ($base_themes as $base_theme) {
  16.                 if (function_exists($base_theme . '_process')) {
  17.                     $existing[$hook]['preprocess functions'][] = $base_theme . '_process';
  18.                 }
  19.                 if (function_exists($base_theme . '_process_' . $hook)) {
  20.                     $existing[$hook]['preprocess functions'][] = $base_theme . '_process_' . $hook;
  21.                 }
  22.             }
  23.         }
  24.     }
  25.  
  26.     // Добавляем препроцессы только для данной темы, они не распространятся на дочерние темы
  27.     if ($theme == 'mytheme') {
  28.         return array(
  29.             // Добавляем регион. Это необходимо, чтобы мы могли использовать шаблоны для регионов
  30.             'region' => array(
  31.                 // Аргументы, которые будут доступны
  32.                 'arguments' => array('elements' => NULL),
  33.                 // Путь к шаблону
  34.                 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
  35.                 // Название шаблона. Полное имя файла будет region.tpl.php
  36.                 'template' => 'region',
  37.                 // Функции, которые будут подготавливать переменные для шаблонизации
  38.                 'preprocess functions' => array(
  39.                     'template_preprocess',
  40.                     'mytheme_preprocess',
  41.                     'mytheme_preprocess_region',
  42.                     'mytheme_process',
  43.                 ),
  44.             ),
  45.             // Выносим header и footer в отдельные шаблоны
  46.             'header' => array(
  47.                 'arguments' => array('elements' => NULL),
  48.                 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
  49.                 'template' => 'header',
  50.                 'preprocess functions' => array(
  51.                     'template_preprocess',
  52.                     'mytheme_preprocess',
  53.                     'mytheme_preprocess_header',
  54.                     'mytheme_process',
  55.                 ),
  56.             ),
  57.             'footer' => array(
  58.                 'arguments' => array('elements' => NULL),
  59.                 'path' => drupal_get_path('theme', 'mytheme') . '/templates',
  60.                 'template' => 'footer',
  61.                 'preprocess functions' => array(
  62.                     'template_preprocess',
  63.                     'mytheme_preprocess',
  64.                     'mytheme_preprocess_footer',
  65.                     'mytheme_process',
  66.                 ),
  67.             ),
  68.         );
  69.     }
  70.     return array();
  71. }


Определим theme_blocks($region). Функция возвращает набор блоков, доступных для текущего пользователя в заданном регионе.
Copy Source | Copy HTML
  1. function mytheme_blocks($region) {
  2.     if ($region) {
  3.         $output = '';
  4.  
  5.         if ($list = block_list($region)) {
  6.             foreach ($list as $key => $block) {
  7.                 $output .= theme('block', $block);
  8.             }
  9.         }
  10.  
  11.         // Контент для данного региона
  12.         $output .= drupal_get_content($region);
  13.  
  14.         $elements['#children'] = $output;
  15.         $elements['#region'] = $region;
  16.  
  17.         // Возвращаем темизированный регион с блоками. Используется region.tpl.php
  18.         return $output ? theme('region', $elements) : '';
  19.     }
  20. }


Определим template_preprocess(&$variables, $hook). Функция подготавливает переменные, которые будут переданы в шаблон.
Copy Source | Copy HTML
  1. function mytheme_preprocess(&$vars, $hook) {
  2.     $key = ($hook == 'page' || $hook == 'maintenance_page') ? 'body_classes' : 'classes';
  3.  
  4.     if (array_key_exists($key, $vars)) {
  5.         if (is_string($vars[$key])) {
  6.             $vars['classes_array'] = explode(' ', $vars[$key]);
  7.             unset($vars[$key]);
  8.         }
  9.     }
  10.     else {
  11.         $vars['classes_array'] = array($hook);
  12.     }
  13.  
  14.     // Тут немного магии.
  15.     // Для каждого хука типа hook_preprocess_anything() мы ищем соответствующий файл
  16.     // в каталоге preprocess и вызываем его
  17.     $name = 'preprocess/preprocess-'. str_replace('_', '-', $hook) .'.inc';
  18.     if (is_file(drupal_get_path('theme', 'mytheme') . '/' . $name)) {
  19.         include($name);
  20.     }
  21. }


Определим HOOK_process() описанный ранее.
Copy Source | Copy HTML
  1. function mytheme_process(&$vars, $hook) {
  2.     if (array_key_exists('classes_array', $vars)) {
  3.         // Сливаем в строку все стили для элемента
  4.         $vars['classes'] = implode(' ', $vars['classes_array']);
  5.     }
  6. }
  7.  


Определим функцию, которая вернет путь к нашей теме.
Copy Source | Copy HTML
  1. function _mytheme_path() {
  2.     static $path = FALSE;
  3.     if (!$path) {
  4.         $matches = drupal_system_listing('mytheme\.info$', 'themes', 'name',  0);
  5.         if (!empty($matches['mytheme']->filename)) {
  6.             $path = dirname($matches['mytheme']->filename);
  7.         }
  8.     }
  9.     return $path;
  10. }
  11.  


Ну и наконец, добавим пару функций для обработки классов и id для страниц
Copy Source | Copy HTML
  1. if (!function_exists('drupal_html_class')) {
  2.     function drupal_html_class($class) {
  3.         $class = strtr(drupal_strtolower($class), array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => ''));
  4.  
  5.         $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);
  6.  
  7.         return $class;
  8.     }
  9. }
  10.  
  11. if (!function_exists('drupal_html_id')) {
  12.     function drupal_html_id($id) {
  13.         $id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
  14.         $id = preg_replace('/[^A-Za-z0-9\-_]/', '', $id);
  15.         return $id;
  16.     }
  17. }


Часть 2, Часть 3
Tags:
Hubs:
+45
Comments 16
Comments Comments 16

Articles