Думаю многие из вас не раз создавали «раскрытый» фильтр в Drupal 7 через views, кто не в курсе, что это и как это создается идем сюда. Данные фильтры помогают нам отфильтровывать ноды, по каким либо параметрам, сейчас же я вам покажу, как самостоятельно можно написать данный фильтр без создания отдельной вьюхи.
Для начала давайте определимся с задачей. Например, создадим кастомную форму, которая должна формировать селект из всех имеющихся у нас типов материалов в системе и кнопку отправки формы. Т.е. мы будем отфильтровывать ноды по типу материала, кроме того усложним задачу и отфильтровывать материалы мы будем через ajax, а так же выведем данную форму в блок.
С задачей определились, теперь для удобства разобьем нашу задачу на этапы разработки:
- Создаем кастомную форму с селектом из типов материалов, существующие в системе и кнопку отправки формы.
- Создаем блок и выводим форму в блок.
- Пишем запросы в БД, исходя из значений фильтра выбранные пользователем
Все действия мы естественно будем производить в своем модуле, как создать свой модуль – читаем здесь. В данном случае, мой модуль я назову – myexposed_filter.
Создаем форму с селектом из типов материалов и кнопку отправки формыКак создаются простейшие формы в Drupal 7 - можно прочитать здесь, я на этом не буду останавливаться.
<?php /** * Implements hook_form */ function myexposed_filter_form($form, &$form_state){ // Получаем список типов материалов в системе $type_content = node_type_get_types(); // Записали в массив типы материалов, где ключами является машинное имя типа материала foreach($type_content as $value){ if($value->orig_type != 'page'){ $options_type[$value->orig_type] = $value->name; } } // Селект с типом материала '#type' => 'select', '#title' => t('Select content type'), '#options' => $options_type, '#empty_option' => '--Select type content--', ); // Кнопка отправки формы '#type' => 'submit', '#value' => t('Filter'), 'callback' => 'myexposed_filter_callback', 'wrapper' => 'myexposed-filter-form', ), ); return $form; }
Хочу заметить, что для кнопки формы мы для Ajax, в качестве келбека отдали функцию myexposed_filter_callback – данную функцию мы опишем ниже
Хочу заметить, что мы убрали из списка типов материалов тип - Страница, ибо формат вывода нод - тизер, а данный тип не имеет тизера.
Создаем блок и выводим форму в блок
<?php /** * Implements_hook_block_info */ function myexposed_filter_block_info(){ // Описали свой блок с фильтром 'info' => t('My exposed filter'), ); return $blocks; } /** * Implements_hook_block_view */ function myexposed_filter_block_view($delta=''){ if($delta == 'myexposed_filter' ){ // Заголовок блока фильтра $block['subject'] = t('My exposed filter'); // Получили форму с указанным названием $block['content'] = drupal_get_form('myexposed_filter_form'); } return $block; }
<?php /** * Callback ajax submit */ function myexposed_filter_callback($form, $form_state){ // Получили значения фильтра $type_content = $form_state['values']['type']; // Проверяем не пустые ли данные значения // Получили список нод для указанного типа $views = node_view_multiple($nodes, 'teaser'); $output = drupal_render($views); }else{ // Получаем NID нод, которые опубликованы и выводятся на главной странице сайта $nids = db_select('node', 'n') ->condition('status', 1) ->condition('promote', 1) ->orderBy('n.created', 'DESC') ->extend('PagerDefault') ->limit(10) ->execute(); // Формируем массив с NID нод foreach ($nids as $nid) { $items[] = $nid->nid; } // Загружаем объекты нод и формирусем формат вывода ноды $nodes = node_load_multiple($items); $views = node_view_multiple($nodes, 'teaser'); // Рендерим список нод и добавляем пагинацию $output = drupal_render($views) .theme('pager'); } // Ajax команды // Изменяем содержимое DOM элемента с указаным ID - на отрендеренный список нод $commands[] = ajax_command_html('#block-system-main', $output); }
<?php /** * Implements_hook_block_info */ function myexposed_filter_block_info(){ // Описали свой блок с фильтром 'info' => t('My exposed filter'), ); return $blocks; } /** * Implements_hook_block_view */ function myexposed_filter_block_view($delta=''){ if($delta == 'myexposed_filter' ){ // Заголовок блока фильтра $block['subject'] = t('My exposed filter'); // Получили форму с указанным названием $block['content'] = drupal_get_form('myexposed_filter_form'); } return $block; } /** * Implements hook_form */ function myexposed_filter_form($form, &$form_state){ // Получаем список типов материалов в системе $type_content = node_type_get_types(); // Записали в массив типы материалов, где ключами является машинное имя типа материала foreach($type_content as $value){ if($value->orig_type != 'page'){ $options_type[$value->orig_type] = $value->name; } } // Селект с типом материала '#type' => 'select', '#title' => t('Select content type'), '#options' => $options_type, '#empty_option' => '--Select type content--', ); // Кнопка отправки формы '#type' => 'submit', '#value' => t('Filter'), 'callback' => 'myexposed_filter_callback', 'wrapper' => 'myexposed-filter-form', ), ); return $form; } /** * Callback ajax submit */ function myexposed_filter_callback($form, $form_state){ // Получили значения фильтра $type_content = $form_state['values']['type']; // Проверяем не пустые ли данные значения // Получили список нод для указанного типа $views = node_view_multiple($nodes, 'teaser'); $output = drupal_render($views); }else{ // Получаем NID нод, которые опубликованы и выводятся на главной странице сайта $nids = db_select('node', 'n') ->condition('status', 1) ->condition('promote', 1) ->orderBy('n.created', 'DESC') ->extend('PagerDefault') ->limit(10) ->execute(); // Формируем массив с NID нод foreach ($nids as $nid) { $items[] = $nid->nid; } // Загружаем объекты нод и формирусем формат вывода ноды $nodes = node_load_multiple($items); $views = node_view_multiple($nodes, 'teaser'); // Рендерим список нод и добавляем пагинацию $output = drupal_render($views) .theme('pager'); } // Ajax команды // Изменяем содержимое DOM элемента с указаным ID - на отрендеренный список нод $commands[] = ajax_command_html('#block-system-main', $output); }
Теперь, вы можете активировать ваш модуль, вывести блок с раскрытым фильтром в необходимый вам регион и смотреть как все работает. Думаю, из комментариев в коде, все должно быть понятно.
Результат работы фильтры:
Скачать готовый модуль можно здесь.
Комментарии (26)
Круто! Спасибо за модуль!
Кстати на мой взгляд было б еще круче если б еще при выборке в адресной строке прописывался путь с переменными типа
www.mysite.ru/?type=page&title=как заработать миллион
опишите свою страницу через hook_menu, которая будет получать значения формы через get, и удалите Ajax. Получите то, что хотите.
эт понятно! Но я имел ввиду, чтоб ajax оставался
Я не ас в программировании. Наверное так сделать вообще невозможно, так что извиняюсь заранее)
именно так - не возможно и не понятно вообще для чего это нужно.
Для того, чтоб пользователь смог скопировать отфильтрованную ссылку и передать/отправить ее кому нибудь.
тогда все равно регистрировать свою страницу, и при формировании формы проверять если данные значения в Get, если есть - то подставлять их в фильтр и рендер производить уже при каждой загрузке страницы.
Я думаю менять содержимое в #block-system-main не совсем корректно, можно что-нибуть лишнее захватить. Да и как минимум content еще надо добавить, а то все стили могут послетать.
ну куда именно загружать результат фильтра все таки зависит от темы, так же как и класс content - это сугубо личное дело каждого. Применять стили к content - не есть гут, ибо он используется Drupal везде, где происходит рендер контента. А так для bartik, замечание имеет смысл.
А можно продолжение статьи сделать о создании нескольких фильтров, среди которых есть поля term reference с несколькими уровнями терминов (например: -Audi, -- A4, -- A6, - BMW, --X5, --X6 итд), думаю будет полезно и интересно :)
Здрасти!
Как заставить работать ajax в раскрытых формах в блоке?
так же как и для страниц, отличий в ajax нет.
помогите понять пожалуйста..
у меня есть несколько раскрытых форм с чекбоксами и выбором цены по диапазону в фильтре в раскрытом блоке, все хорошо, но есть одно но, я не хочу чтоб при выборе или отправки перезагружалась стр., я хочу чтоб стр. работала на ajax, как мне это реализовать?
а почему аякс в формах работает только в содержимом а не в блоке?
Ajax работает с любым DOM элементом страницы. В drupal есть свои ajax команды, в частности команда
выберет элемент с классом test и заменит его на текст "текст для замены". Только вы определяете, что на что менять.
тогда почему когда я переключаю во view галочку на "Раскрытая форма в блоке:Да", форма появляется в регионе но аякс не работает?
так и сказали бы, что используете view. Не думаю, что при таком раскладе должен срабатывать Ajax в views. Хотя нужно посмотреть.
я так понимаю для того чтоб он заработал надо писать модуль?
Здравствуйте!
Как сделать во view расположение view-filters и view-content в разных регионах?
view-filters в левой колонке а view-content соответственно оставить как есть.
в настройках views, поставить галочку напротив использовать "Использовать раскрытую форму в блоке" и далее этот блок вывести в необходимом вам регионе.
Да спасибо, я в курсе, у меня так и сделано но мне нужно чтоб стр. работала без перезагрузки по ajax, ajax соответственно вкл.
по идеи тогда должен работать и ajax. Посмотрите, сработает ли ajax на базовой теме.
У меня две вьюхи:
1 каталог (catalog/%) где выводится только продукты
2 фильтр (filter) с настройками раскрытых фильтров в блоке
все работает и фильтруется, но с перезагрузкой на стр. (filter) а вот ajax не пашит ((
Но если я выключаю view с каталогом и добавляю отображение блок к view с фильтрами page и вывожу этот блок в содержимое, то ajax работает, но весь вывод получается в регионе содержимого а мне нужно чтоб фильтры были в левой колонке а продукты в правой тобишь в регионе содержимого
Вообщем удалил я view filter и оставил только view catalog с видом page, раскрыл все фильтры, вывел их через better_exposed_filters, что в левой колонке что в содержимом ajax не работает, менял на базовые тему, без изменений, в чем может быть дело???