Небольшой путеводитель по написанию модуля для Drupal 7.
Любой «приличный» проект на drupal (да и в других CMS) требует как минимум трех вещей:
- Взять подходящую сборку drupal (с нужными модулями, установленным Wysiwyg редактором, русификацией);
- Создать тему оформления (свою собственную или с использованием одного из готовых шаблонов);
- Запрограммировать весь дополнительный функционал сайта, который не смог быть реализован в п.1 в собственном модуле (модулях).
О последнем пункте, о том как написать свой модуль мы и поговорим.
Речь идет не о создании модуля для распространения через репозиторий проектов Drupal.org, а о частном модуле для хранения функционала, написания зацепок (hook) для одного из ваших проектов.
Типичный набор файлов модуля
«Сначала было слово…».
Нужно определиться с названием модуля. Все файлы модуля хранятся в папке, которую для него создают в директории /sites/all/modules. Движок найдет ваш модуль также при размещении в — /modules, где хранятся модули ядра и в — /sites/default/modules.
Пусть наш модуль называется newmodule. Создадим для него папку — /sites/all/modules/newmodule.
Движок узнаёт о наличие модуля по файлу с расширением .info. А основные функции и зацепки (hooks) нужно описывать в файле .module. Создадим оба этих файла:
1 2 |
newmodule.info newmodule.module |
Здесь же могут содержаться все остальные необходимые модулю файлы.
Реализацию зацепок по установке, удалению и обновлению модуля обычно помещают в файл .install.
1 |
newmodule.install |
Структура файла .info
Файл-описатель .info — это текстовый файл. Он состоит из набора записей — свойств модуля. Лучшая практика — скопировать описатель уже существующего модуля и просто его отредактировать.
Для примера приведу содержание инфо файла для модуля imce:
1 2 3 4 5 |
name = "IMCE" description = "An image/file uploader and browser supporting personal directories and user quota." core = "7.x" package = "Media" configure = "admin/config/media/imce" |
Файл может содержаться следующие описания (свойства), но лишь некоторые из них являются обязательными:
- name (обязательно) — название модуля;
- description — краткое описание не более 255 симв., может содержать гиперссылки (тег <a>);
- core (обязательно) — требуемая версия ядра друпал (обычно «6.x», «7.x» и т.п.);
- stylesheets — файлы css, дополнительно подключаемые модулем. Формат записи —
stylesheets[all][] = mystyle.css
, если файл находится в корне папки модуля; - scripts — файлы js скриптов, подключаемые модулем, пример —
scripts[] = script.js
; - files — подключит ещё какие то файлы, помимо .module, пример —
files[] = tests/example.test
; - dependencies — перечисляются другие модули, которые требуются для работы данного, пример —
dependencies[] = taxonomy
— здесь мы говорим, что для модуля требуется активный модуль таксономии. Возможны и более сложные описания требований (к примеру, указание версии требуемого модуля); - package — для группировки модулей можно указать название «пакета». Это удобно, когда просматриваешь список модулей проекта, и они как то сгруппированы;
- php — мин. версия PHP, требуемая для работы;
- version — можете указать версию модуля;
- configure — для списка модулей, здесь можно указать путь страницы конфигурации модуля;
- required — модуль отмеченный как «обязательный» нельзя будет отключить в списке модулей (
required = TRUE)
; - hidden — указание не показывать в списке модулей (
hidden = TRUE
); - project — тут можно указать название проекта. Но если вы опубликовали модуль на drupal.org, то этот параметр будет заполняться автоматически и его задавать не надо;
- project status url (используется только модулями не опубликованными на drupal.org).
Как видите, требуется написать буквально пару строк.
1 2 |
name = New Module core = 7.x |
Содержание основного файла модуля — .module
Вот мы и добрались до основного блюда. Файл .module — это PHP скрипт. Здесь мы рассмотрим наиболее часто используемые hooks, программируемые в drupal. Т.к. функционал модуля — это уже ваша забота, я покажу лишь название зацепок и некоторые каркасы функций. Что вы будет использовать, я что нет — зависит только то вас :)
Программируем страницы в Drupal 7 (hook_menu)
Эта зацепка позволяет добавить в навигацию движка нужные вам страницы (их адреса url, заголовки, содержание). Так вы можете создать страницы front/back — end, а также специальные разделы, вроде обработки запросов по ajax, реализовать программные интерфейсы сайта (к примеру, с ответами в виде XML) и т.п.
Программирование блоков в Drupal 7
Нужные страницы мы запрограммировали, теперь создадим свои блоки. Зацепок, связанных с блоками много, но я выделил пару без которых просто не обойтись:
hook_block_cid_parts_alter | |
hook_block_configure | создание настроек для блоков; |
hook_block_info | объявление блоков; |
hook_block_info_alter | |
hook_block_list_alter | |
hook_block_save | сохранение данных конфигурации, созданной hook_block_configure; |
hook_block_view | формирует и возвращает содержание блоков; |
hook_block_view_alter | |
hook_block_view_MODULE_DELTA_alter |
Я не акцентирую внимание на всех хуках, т.к. не собираюсь создавать всеобъемлющий гайд (это будет дело всей жизни), но по названию вы уже может и сами поискать информацию. Есть для семерки полный перечень хуков ядра.
Процесс сводится к программированию нескольких зацепок, чаще всего это — hook_block_info, hook_block_view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/* Объявим наши блоки */ function newmodule_block_info() { $blocks['myblock'] = array( 'info' => t('А это описание блока, которые вы увидите в списке блоков'), 'cache' => DRUPAL_NO_CACHE, ); //для объявления блока нужно всего лишь параметр 'info' - описание $blocks['one_more_block'] = array( 'info' => t('Ещё один блок'), ); return $blocks; } /* Далее необходимо запрограммировать блоки Мы объявили пару из них в hook_block_info */ function newmodule_block_view($delta = '') { $block = array(); switch ($delta) { case 'myblock': $block['subject'] = t('Заголовок блока'); //содержание блока может быть сложным $block['content'] = array( '#theme' => 'feed_icon', '#url' => 'rss.xml', '#title' => t('Syndicate'), ); break; case 'one_more_block': //содержание блока может быть просто HTML кодом //и не иметь заголовка if (user_access('administer content types')) { $block['content'] = t('Content available.'); } else { $block['content'] = t('You have no access to this block.'); } break; } return $block; } |
Элементы node API
Рассмотрим ещё набор зацепок для работы с нодами (node hooks).
hook_node_access | проверка доступа к публикации |
hook_node_access_records | после записи ноды, можно уточнить права доступа к ней |
hook_node_access_records_alter | |
hook_node_delete | вызывается при удалении ноды |
hook_node_grants | здесь можно проинформировать, какие права имеет пользователя для доступа к публикациям |
hook_node_grants_alter | |
hook_node_info | этот модуль позволяет программно объявлять типы публикаций |
hook_node_insert | вызывается при создании новой публикации |
hook_node_load | вызывается при загрузке публикации из БД |
hook_node_operations | добавление собственных массовых операций в раздел admin/content |
hook_node_prepare | правка объекта ноды перед показом в редакторе публикации (форма добавления/редактирования ноды) |
hook_node_presave | вызывается перед записью ноды в БД |
hook_node_revision_delete | зацепка за удаление версии ноды (т.н. ревизии) |
hook_node_search_result | вызывается при показе публикации в результатах поиска (можно добавить ещё какую то информацию) |
hook_node_submit | вызывает при отправке данных редактора формы, тут можно зацепить функционал не связанный с field API |
hook_node_type_delete | зацепка при удалении описания типа публикаций |
hook_node_type_insert | зацепка при добавлении типа публикаций |
hook_node_type_update | зацепка при обновлении типа публикаций |
hook_node_update | активируется при обновлении публикации |
hook_node_update_index | выполняется при при индексации для поиска по сайту |
hook_node_validate | зацепка для программной валидации значений полей перед созданием или обновлением публикации |
hook_node_view | вызывается перед перед тем как создан массив для рендеренга ноды, т.е. тут мы имеет дело с объектом node |
hook_node_view_alter | а эта зацепка позволяет внести изменения в рендер-массив ноды (подготовленный для drupal_render) |