УрокПишем плагин к Panels с помощью Ctools
Не так давно я очень плотно подружился связкой модулей Views + Panels + Page manager (входит в Ctools). Как оказалось, с их помощью можно много времени сэкономить на многих задачах. В добавок ко всему производительность отличная (выяснилось, что Panels работает быстрее, чем стандартные блоки ядра). Вдохновиться можно посмотрев скринкасты по работе с этой связкой. Живой пример могу показать на примере своей работы - footballtop.ru. Около 90% страниц построено именно на этой связке.
В общем, ближе к теме разговора. Передо мной стояла задача написать не совсем обычную форму голосования, со своими плюшками. Далее эту форму надо было закинуть через Panels в материалы, т.к. все ноды были уже переделаны с помощью панелей, и hook_node_view() уже не срабатывал. Саму реализацию голосования я оставлю за рамками статьи, а вот на написании плагина остановлюсь подробнее.
Первое, на что я бы хотел обратить внимание - это то, что для Panels плагины не пишутся. Они пишутся с помощью API модуля Ctools. Поэтому по сути, плагин пишется именно к Ctools (или с его помощью, как вам угодно), а далее он нам будет автоматически доступен при работе с Panels через веб интерфейс.
Итак, давайте пошагово пройдёмся по этапам создания плагина.
Шаг первый. Описываем папку с плагином.
Первым делом надо указать в какой папке будут храниться плагины. По традиции они хранятся в папке plugins внутри модуля. Папка указывается с помощью имплементирования в модуле хука hook_ctools_plugin_directory(). После описания папки, Ctools автоматически подхватит все плагины из неё.
/** * Implements hook_ctools_plugin_directory(). */ function ИМЯМОДУЛЯ_ctools_plugin_directory($owner, $plugin_type) { if ($owner == 'ctools') { return 'plugins/' . $plugin_type; } }
Здесь надо отметить, что плагины хранятся не сразу в директории plugins, а они ещё и по категориям разбиты разбиты. Вот список категорий:
- access - плагины к уровням доступа. Позволяют указывать проверки, при которых пользователь получит или не получит доступ к содержимому.
- arguments - плагины, описывающие возможные аргументы, которые можно получить из урла страницы.
- cache - плагины, описывающие возможные механизмы кэширования.
- content_types - плагины, которые выводят содержимое. Например, элементы материала, формы, произвольно заданное содержимое и т.д.
- context - плагины, описывающих возможные контексты, которые могут быть использованы в настройках панелей или передаче их в другие сущности.
- relationships - плагины, описывающие возможные взаимосвязи между сущностями.
Так как в моём случае надо было писать плагин по выводу содержимого, то он у меня хранился по адресу plugins/content_types/ftop_vote_widget.inc, где ftop_vote_widget - название плагина.
Шаг второй. Предоставляем информацию о плагине.
Сразу в начале файла, после открывающегося тэга <?php
(без оборачивания в функцию) пишется описательная часть плагина. В примере я добавил проверку на существование модуля, в котором содержится весь функционал голосования:
if (module_exists('ftop_vote')) { $plugin = array( 'single' => TRUE, 'title' => t('FootballTop Vote Widget'), 'description' => t('Voting widget for footballtop.ru.'), 'category' => t('Node'), 'render callback' => 'ftop_vote_widget_content_type_render', 'required context' => new ctools_context_required(t('Node'), 'node'), ); }
Таким образом я смог сказать Ctools, что мой плагин должен быть помещён в категорию Node, и для его подключения ему необходимо передать объект ноды из контекста (если в контекстах ноды не будет, то я не смогу выбрать этот плагин). Однако я использовал не все параметры в описании, которые доступны. Вот более полный список:
$plugin = array( // Название плагина, которое будет отображено при его выборе. 'title' => t('Simplecontext content type'), // Описание плагина, которое будет отображено при его выборе. 'description' => t('Simplecontext content type - works with a simplecontext context.'), // Конструктор. 'content_types' => 'simplecontext_content_type', // Показывает, является ли плагин подтипом другого. В данном случае - не является. 'single' => TRUE, // Название функции, которая будет создавать блок с данными. 'render callback' => 'simplecontext_content_type_render', // Иконка, отображаемая при выборе плагина. 'icon' => 'icon_example.png', // Контекст, который необходимо передать плагину для его работы. 'required context' => new ctools_context_required(t('Simplecontext'), 'simplecontext'), // Форма с дополнительными настройками плагина. 'edit form' => 'simplecontext_content_type_edit_form', // Административный заголовок модуля, который может быть изменён через веб интерфейс. 'admin title' => 'ctools_plugin_example_simplecontext_content_type_admin_title', // Создаёт блок предпросмотра результата в Panels. 'admin info' => 'ctools_plugin_example_simplecontext_content_type_admin_info', // Категория, в которую будет помещён плагин, и его вес. 'category' => array(t('CTools Examples'), -9), // Контексты, передаваемые по умолчанию. 'defaults' => array(), );
Шаг третий. Реализуем функции из описания плагина.
В моём это только одна функция - ftop_vote_widget_content_type_render(), которая с помощью полученных в Panels данных подгружает форму с голосованием:
/** * Render the custom content type. */ function ftop_vote_widget_content_type_render($subtype, $conf, $panel_args, $context) { // На всякий случай, если вдруг контекст был, плагин включили, а потом контекст убрали. if (empty($context) || empty($context->data)) { return; } // Забираем нашу ноду из контекста. $node= $context->data; // Создаём блок с формой и передаём ей ноду. $block = new stdClass(); $block->module = 'ftop_vote'; $block->content = drupal_get_form('ftop_vote_form', $context->data); return $block; }
Эта функция получает следующие параметры:
- $subtype - используемый подтип. В моём случае его нет, поэтому будет передано 'ftop_vote_widget'.
- $conf - массив с пользовательскими настройками плагина. По умолчанию здесь может быть только заголовок блока, но если вы описывали форму с дополнительными настройками - то они окажутся в этом массиве.
- $panel_args - аргументы, которые были переданы в Panels в их необработанном виде.
- $context - контексты, который (или которые) выбрал пользователь для передачи в плагин.
Вот, собственно, и всё. В итоге плагин с описанием директории и его самого у меня занял ровно 36 строк кода (и это вместе с комментариями и отступами!). Совсем немного, для подключения модуля к такой машине, как Panels, не так ли ? :)
- Spleshka
- 02.05.2012
- 19023
Комментарии
хорошо было бы почитать про связку Views + Panels + Page manager подробнее. так сказать "на пальцах". всегда делал шаблоны через regions+block. скринкаст на node 1 смотрел, как раз по ним и понял, что связка довольно мощная. не планируешь написать парочку статей по теме? может даже на примере сайта footballtop.ru
Так а что писать-то про неё? nodeone шикарно раскрывают всё в скринкастах. Можно только рабочие примеры показывать, не более того. Или есть особые пожелания?
ну да, можно взять пример и сравнить подходы, как это делается без связки (обычно) и как это же сделать со связкой. тут будет видна разница как по времени так и по производительности (возможно). по сути я имею ввиду статью по подходам, ведь в Drupal одну и ту же вещь можно сделать многими путями.
Скринкаст больше не доступен :(
Может переложили куда? Есть ссылки?
Буду признателен :)
Прошу прощения, был не совсем внимателен.
Рабочие ссылки на скринкаст есть в блоке слева, а в теле новости ссылки таки битые.
> Как оказалось, с их помощью можно много времени сэкономить на многих задачах
например?
> выяснилось, что Panels работает быстрее, чем стандартные блоки ядра
цифры?
Пример - http://www.footballtop.ru/players/lionel-messi. На этой связке не только вывод всего содержимого ноды, но и содержимое остальных вкладок, которые к этой ноде относятся. Настраивается за час совместно с настройкой вьюсов для этих вкладок и хлебных крошек к странацам.
Цифры не считал, но по общим ощущениям быстрее. Ты ж не забывай, что блоки построены таким образом, что они для каждой страницы сначала дёргаются все, а уже потом раскладываются по своим регионам. А в панелях вызывается непосредственно нужный блок. Соответственно в этом и выигрыш по производительности.
Сайт по общим ощущениям действительно работает быстро!
По поводу голосований было бы интересно почитать. Я вижу Voiting API и FLAG как 2 стороны вопроса. У вас ни того, ни другого не спалила.
Зря не спалили) У меня голосование как раз на Voting API построено.
ну его не особо видно, форма и форма :)
Правильно, обёртка-то моя. А вот API чужой =)
большое спасибо за труд , последние три статьи очень вовремя вышли ).
Это в отдельном модуле , в all/modules ?
Пример полный , работать будет при воспроизведении ?
Да, в отдельном модуле.
Пример не полный, я в начале об этом писал. Но если поменять форму ftop_vote_form на любую другую, то работать будет.
> Первое, на что я бы хотел обратить внимание - это то, что для Panels плагины не пишутся.
Пишутся. Для Panels можно делать layout и style плагины. Это очень удобно, когда нужно вывести данные в каком то нестандартном шаблоне. Вместо того, чтобы переопределять через темизацию стандартные шаблоны и стили, можно сделать свой плагин. Причём, для этого не нужно писать свой модуль. Плагины могут находится внутри темы оформления.
Это не совсем те плагины, которые я имел ввиду. Но замечание ценное, а то могут решить что вообще плагинов больше нет к панелям :)
Небольшой офтоп.
А как, если не секрет, вы реализовывали рейтинг игрока http://www.footballtop.ru/players/lionel-messi в смысле снятия ежедневных данных по ноде и переносу на график.
Сделай пожалуйста урок который научил бы делать такое же меню как на этом сайте footballtop.ru
Я создал плагин, все получилось. Но! Теперь я хочу создать еще одни.
Для этого создаю для него файлик $user_profile.inc, который находится в "plugins/content_types". В этом файле описываю плагин по инструкции. Но он не появляется там где должен.
То есть 1-й созданный плагин работает как нужно, 2-й созданный плагин в том же модуле вообще не появляется. Почему его может не быть?
Как правильно создавать в одном модуле несколько плагинов?
Уже разобрался. Проблема была в имени. Почему-то нельзя называть файл с плагином вот так - "user_profile.inc"
Зашел на footballtop.ru Так как у меня заблокированы скрипты меня перенаправили на страницу http://www.footballtop.ru/badbrowser.html. ок. Временно разрешил скрипты на этом сайте. Нажимаю "обновить страничку" И... ничего не меняется Пока принудительно не догадался вырезать из адреса badbrowser.html. Автор, по моему вы теряете с таким подходом посетителей. Не многие буду разбираться почему у них не открывается сайт. А после обнвления страницы badbrowser.html сайт сам должен перенаправлять на главную в случае если js уже включили. Это просто мой совет
ps
А тут и капчу с первого раза не введешь... Как надежно все запечатано :)
pps
Дубль три при попытке ввести коммент.
Теперь оказывается нельзя потому что "Пользователь с таким именем уже есть" тяжело к вам достучаться :)
Комментировать