Опять четверг, опять кафе.
В четверг, 24 мая, в 19:00, в Харькове пройдет пятое DrupalCafe.
На этот раз мы сменили место проведения, мероприятие пройдет по адресу ул. Маломясницкая, д 9/11, Академия “Шаг”. (станция метро “Проспект Гагарина”).
Карта
Темы докладов:
1. "Знакомство с модулем Views" (Алексей Гайдабура, WDG)
- Архитектура Views.
- Основы работы с Views.
- Для чего нужны CONTEXTUAL FILTERS и RELATIONSHIPS.
- Разное, непонятное.
2. "Form API в Drupal 7. "Вкусности" и "красоты" (Дмитрий Олареско, WDG)
Данная тема познакомит Вас с особенностями Form API в Drupal 7. Расскажет о нововведениях и интересных приемах, которые могут пригодится как начинающему так и опытному программисту.
3. "Секция-Вопросы&Ответы."
В этот раз третий слот посвящен любым вопросам от посетителей. Вопросы можно прикреплять в комментариях, либо присылать на контактный e-mail.
Участие бесплатное, в программе как обычно, вкусные угощения - кофе, чай, блекджек, cookies.
Желательно предварительная регистрация, всем желающим - отпишите в комментарии или в контакты ниже.
Регистрация по ссылке
По всем вопросам можно обращаться:
+38(099)35-25-316 - Алексей Гайдабура, gaydabura@gmail.com skype: alexey.gaydabura
Спонсор по прежнему - WDG (http://wdg-company.com/)
На сайте CMS Magazine перевод статьи "Create a responsive Drupal theme" о создании темы оформления для D7 адаптируемой к разным разрешениям экрана. По-моему полезная статья. Отдельное спасибо сотрудникам CMS Magazine за адекватный перевод.
Ссылка на перевод статьи: http://www.cmsmagazine.ru/library/items/cms/create-responsive-drupal-theme/
В Новосибирске планируется третье долгожданное DrupalCafe 26 мая.
Ждем всех желающих!
Можете участвовать в активном обсуждении выступлений и предложений дальнейшего развития Drupal-сообщества, разработок и новостей.
Можете выступить сами со своей темой подготовив презентацию.
Предварительные темы докладов:
Павел Прищепа выступит с докладом о DrupalSib at Kharkov Drupal {code} sprint
Чингис Санданов расскажет о mongoDB
Предварительная обязательная регистрация
г.Новосибирск, Академгородок, ул. Инженерная 20, Технопарк, конференцзал на 3 этаже
Начало: 26 мая в 12:00
Окончание:26 мая в 16:00
Помощь в подготовке докладов Роман Чижиков: skype: roman.chizhikov
Организационные вопросы: Павел Прищепа: skype: prischepa.p, Анна Шевцова: skype: anna.newsib
info@drupalsib.ru
тел.офиса (383) 233-27-00
Итак, настала пора планировать следующее мероприятие.
Ориентировочно пройдет оно в том же помещении, что и первая встреча - антикафе Бабочки.
По датам предварительно ориентируюсь - 16, 17, 23 или 24 мая (дату еще корректирую в зависимости в том числе и от ваших замечаний).
По времени с 19 до 23.
Темы для обсуждения выложу чуть позже, если предложите что-то интересное - велкам!
http://u6167.moko.vps-private.net
Введение.Модуль Acar позволяет манипулировать содержимым корзины ubercart. Это всевозможные поля и кнопки, для отображения и изменения параметров, помещенных в корзину продуктов.
Все манипуляции, над содержимым корзины осуществляются мгновенно, согласованно с сервером через AJAX. Без перезагрузки страницы.
В отличии, от стандартной корзины ubercart, мы не ограничены одной формой корзины, на её странице. С помощью Acar, можно создать сколько угодно, форм корзины, где угодно, в любом месте документа.
Acar корзину можно темизировать. Придавая ей, уникальный вид, по всем правилам html. Тем самым реализуя, любые дизайнерские задумки.
Использование.Для работы модуля Acar, необходим модуль Mvca. Этот модуль является отдельным проектом, и реализует собой MVC паттерн. Скачать оба модуля можно с официального сайта Acar корзины.
Сразу после установки, форма корзины, доступна в двух местах. На своей собственной странице /acar. И на стандартной странице корзины ubercart, в виде дополнительной панели. Настроить панели, можно в настройках ubercart /admin/store/settings/cart/panes. Обе эти формы темизируется шаблоном из файла acar_pane.tpl.php.
Ещё одна форма корзины доступна как блок. Который необходимо предварительно активировать. А темизируется она, шаблоном из файла acar_bloc.tpl.php.
Для добавления продукта в корзину, со страницы продукта, а так же со страницы каталога имеются специальные field и views поля: "Acar - Form add product to cart". Позволяющие создать форму добавления. Для этих полей в настройках, необходимо самостоятельно указывать используемый файл шаблона. Он может быть любым, но по идеи это должены быть файлы acar_adde.tpl.php для field поля, и acar_view.tpl.php для views поля. Для управления field полями в типе материала необходимо включить модуль Field UI.
Поиск файлов шаблонов, осуществляется в каталоге текущей темы оформления. Если какой либо из них, там отсутствует, то берётся файл шаблона с тем же именем из каталога модуля Acar.
В модуле Acar, в каталоге samples, вы можете найти несколько образцов шаблонов. Чтобы приступить к темизации Acar корзины, нужно скопировать файлы шаблонов, в каталог темы оформления, вместе со всеми прилагаемыми к ним файлами картинок и стилей. И уже там, изменяя их, придавать корзине требуемый вид. Не забудьте только, очистить кэш.
Темизация.Файл шаблона, темизирующий форму корзины или форму добавления, представляет из себя, самый обыкновенный javascript. Где инициализируется ряд переменных, в целом и отвечающих за темизацию.
Это текстовые переменные. А именно, так называемый шаблон список (Lis) и шаблон пункт (Ite). Оба этих шаблона содержат html код, на основе которого и конструируется форма корзины или форма добавления.
Шаблон список (Lis) - это шаблон своего рода ёмкости для продуктов, и необходим исключительно для формы корзины. В то время как шаблон пункт (Ite) - это шаблон отдельного продукта, и применяется как для формы добавления, так и для формы корзины.
При темизации формы корзины, что бы было понятно, в какой именно элемент корзины вставлять продукты, этот самый элемент, в шаблоне список, следует пометить классом $$Par. Однако если требуется вставлять продукты не внутрь элемента, а перед каким либо элементом, то такой элемент следует пометить классом $$Chi.
Для наделения, какого либо элемента способностью отображать или изменять параметры продукта или корзины, этот самый элемент необходимо оснастить соответствующим функционалом. Осуществляется это за счет передачи через атрибут class функционала, который необходимо внедрить в элемент.
Оформляется подобное внедрение внутри атрибута class, следующим образом:
@fun(arg0,arg1,arg2,...)
В начале, символ '@', далее идентификатор функции, после него, в скобках перечисляются аргументы. Избегайте использования пробелов, вместо них лучше использовать юникод пробел '\u0020'.
Например, следующий input элемент, размещённый в шаблоне пункта (Ite), при помощи функции qty, позволит отобразить или изменить количество продукта.
<input class="@qty(true)"/>
Эту функцию, как и любую другую, можно применить к любому элементу, например к div. Количество продукта будет так же отображаться, но изменить его, по понятным причинам уже не получится.
<div class="@qty(true)"></div>
Для отображения или изменения параметров корзины или продукта, предоставлено множество функций. В один элемент может быть внедрено сразу несколько функций, однако будьте внимательны, комбинации некоторых функций могут перекрывать работу друг друга, хотя и не вызовут ошибок.
Функционал.Функция tot.
@img(exe) <span></span> Ite
Выводит изображение продукта.
exe - Условие использования*.
Функция tot.
@tit(exe) <a></a> Ite
Отображает название продукта как ссылку.
exe - Условие использования*.
Функция qty.
@qty(exe) <input type="text"/> Ite
Отображает и изменяет количество продукта.
exe - Условие использования*.
Для формы добавления, эта функции позволяет не просто изменить количество продукта, но и добавить или удалить продукт из корзины.
Функция qtc.
@qtc(exe, qtc) <input type="button"/> Ite
Изменяет количество продукта при щелчке, на определенную величину.
exe - Условие использования*.
qtc - Величина на которую следует менять количество продукта.
Применяется, как правило, к элементу кнопки. Для формы добавления, эта функция не просто изменяет количество, но и когда это имеет смысл, добавляет или удаляет продукт из корзины.
Особенностью данной функции, как и некоторых других предназначенных специально для кнопок, является обработка события нажатия. При котором фоновое изображение, сдвигается вниз и вправо на 1 пиксель, когда кнопка нажата.
Функция pri.
@pri(exe, sig, frm) <input type="text" readonly/> Ite
Отображает стоимость одного экземпляра продукта.
exe - Условие использования*.
sig - Знак валюты*.
frm - Формат числа*.
Функция tot.
@tot(exe, sig, frm) <input type="text" readonly/> Ite
Отображает стоимость количества продукта.
exe - Условие использования*.
sig - Знак валюты*.
frm - Формат числа*.
Функция abs.
@abs(exe, sig, frm) <input type="text" readonly/> Ite Lis
Отображает общую стоимость всего содержимого корзины.
exe - Условие использования*.
sig - Знак валюты*.
frm - Формат числа*.
Функция tra.
@tra(exe, tra) <input type="button"/> Ite
Осуществляет переход при щелчке, на страницу продукта или по указанному адресу.
exe - Условие использования*.
tra - Адрес для перехода.
Функция atr.
@atr(exe, cla, sty) <span></span> Ite
Выводит атрибуты продукта.
exe - Условие использования*.
cla - Класс, определяет способ вывода атрибутов.
sty - Стиль*, применяемый к атрибутам.
Доступно два класса: Acar.Atri.Atri и Acar.Atri.Imge. Класс Acar.Atri.Atri позволяет отображать атрибуты, так же как и в стандартной форме добавления. Класс Acar.Atri.Imge выводит описание значений атрибутов в виде списка.
Стиль применяемый к атрибутам, устанавливает для элементов составляющих атрибуты стиль, класс, или значение атрибутов. Тем самым, позволяя темизировать атрибуты. Для обоих классов имеется соответствующий каждому стандартный стиль.
Стили для класса Acar.Atri.Atri:
Acar.Atri.Atri.Sty.Def - Используется по умолчанию.
Стиль для класса Acar.Atri.Imge:
Acar.Atri.Imge.Sty.Def - Используется по умолчанию.
Acar.Atri.Imge.Sty.Min - Красивый стиль с мелкими буквами.
Функция sty.
@sty(exe, sty) <div></div> Ite
Накладывает на элемент указанный стиль.
exe - Условие использования*.
sty - Стиль* применяемый к элементу.
Функция out.
@out(exe, exp) <span></span> Ite Lis
Выводит результат javascript выражения.
exe - Условие использования*.
exp - Выражение javascript, в виде строки.
Например, можно вывести результат выражения 2*(56*3+5):
<div class="@out(true,\'2*(56*3+5))\'"></div>
Или.
<input class="@out(true,\'2*(56*3+5))\'" type="text"/>
Разумеется, таким образом можно выполнить любой javascript код, вывести значение любой переменной. Так что, эта функция может быть весьма полезна. Не забывайте только что передаваемое выражение обязательно должно быть строкой, а уже в ней собственно javascript.
Продолжение покупок.
Для создания ссылки на страницу продолжения покупок, какой либо специальной функции нет. Вместо этого имеются переменные, хранящие в себе текст и адрес. Используя их можно вывести как ссылку, так и кнопку для перехода на страницу продолжения покупок.
Acar.Reso.Prm.Csh.Tex
Текст, обозначающий продолжения покупок, по умолчанию "Continue shopping".
Acar.Reso.Prm.Csh.Url
Адрес страницы, для продолжения покупок.
Для создания ссылки на страницу продолжения покупок, нужно воспользоваться функциями out и sty:
<a class="@out(true,\'Acar.Reso.Prm.Csh.Tex\') @sty(true,{href:Acar.Reso.Prm.Csh.Url})"></a>
Либо не совсем корректным, но надежным способом, "разорвав" шаблон и осуществив конкатенацию:
<a href="'+Acar.Reso.Prm.Csh.Url+'">'+Acar.Reso.Prm.Csh.Tex+'</a>
Для создания кнопки понадобятся функции out и tra:
<input class="@out(true,\'Acar.Reso.Prm.Csh.Tex\') @tra(true,Acar.Reso.Prm.Csh.Url)" type="button"/>
Переменная Acar.Reso.Prm.Csh.Url хранит ссылку, только если ранее продукт был добавлен. Поэтому рекомендуется настроить страницу для продолжения покупок, в настройках ubercart.
*Условие использования.
Аргумент условие использования, передается абсолютно во всех функциях. С его помощью, можно настроить при каких обстоятельствах следует внедрять функцию в элемент.
Это либо логическое значение, которое достаточно однозначно говорит, следует ли применять к элементу данную функцию. Либо строка содержащая в себе javascript выражение, из которого доступны следующие переменные булиевого типа:
vie.add - Истинно если это форма добавления.
vie.car - Истинно если это форма корзины.
inc - Подтверждает наличие продукта в корзине.
exc - Подтверждает отсутствие продукта в корзине.
atr - Подтверждает наличие у продукта атрибутов.
Например, имея дело с формой добавления, для того что бы элемент имел различную раскраску в зависимости, от наличия продукта в корзине, можно использовать следующий функционал:
<div class="@sty(\'inc\',\'background:#faa;\') @sty(\'exc\',\'background:#05f;\')">-=DIV=-</div>
*Знак валюты.
Аргумент знак валюты используется в функциях вывода стоимости.
Если это false знак валюты не выводится, если true выводится знак валюты настроенный в ubercart.
Если же, в качестве знака валюты передается массив. То первый аргумент определяет собственно знак валюты в виде строки, а второй аргумент его расположение, в виде логического значения, слева или справа, от цены.
Например, вывод общей стоимости всех продуктов.
Без знака валюты:
<input class="@abs(true,false,false)" readonly/>
Со знаком валюты настроенным в ubercart:
<input class="@abs(true,true,false)" readonly/>
Наш вариант, где знак валюты 'Руб.' и расположен он справа от цены:
<input class="@abs(true,[\'Руб.\',true],false)" readonly/>
Если вдруг возникнет необходимость просто вывести сам по себе знак валюты настроенный в ubercart, можно воспользоваться функцией out, и непосредственно переменной хранящей знак Acar.Reso.Prm.Cur.Sig:
<span class="@out(true,\'Acar.Reso.Prm.Cur.Sig\')"></span>
*Формат числа.
Аргумент формат числа, применяется в функциях вывода стоимости чего либо.
Если это false, выводится число как есть, без всякой обработки, если true, используется формат, установленный в настройках ubercart.
Передавая массив, мы можем определить свой собственный формат числа. Первый аргумент задает количество десятичных знаков. Второй аргумент десятичный разделитель. Третий аргумент разделитель тысяч.
*Стиль
Некоторые функции используют в качестве аргумента, так называемый стиль. При помощи которого, для элемента и его потомков, можно установить значение класса, стиля, и атрибутов. Следует понимать, что стиль применяется уже после того как элемент создан.
Способы передачи стиля: класс, стиль, атрибуты.
• Класс.
Строка содержащая название класса.
<div class="@sty(true,\'classname\')">...</div>
• Стиль.
Строка содержащая css стиль. Должна обязательно заканчиваться символом ';'.
<div class="@sty(true,\'background:#ffaa00;\')">...</div>
• Атрибуты.
Объект, каждое из свойств которого соответствует атрибуту.
<a class="@sty(true,{href:\'http://www.drupal.ru\'}>LINK</a>
Данным способом можно установить любой атрибут элемента. Атрибут передается в виде строки.
Что бы обеспечить гибкость, имеется несколько уникальных дублирующих свойств:
$Typ - Соответствует атрибуту type.
$Nam - Соответствует атрибуту name.
$Cla - Соответствует атрибуту class (className).
$Sty - Соответствует атрибуту style (style.cssText).
Для применения стиля к дочерним элементам, предназначено свойство $Chi. Представляющие собой массив стилей. Каждый из них применяется, в зависимости от его порядка, с периодичностью по кругу, к соответствующему дочернему элементу.
Благодаря тому что стили применяются с периодичностью по кругу. Дочерние элементы, можно раскрасить разными "цветами", в зависимости от порядка элемента, например "четный/нечетный".
<div class="@sty(true,{$Chi:[\'black\',\'white\']})"><p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p></div>
27 апреля Яндекс выпустил модуль оповещения себя об обновлении/добавлении новых страниц на сайт:
http://site.yandex.ru/cms-plugins/?from=wmblog
Модуль подходит для всех популярных CMS, в т.ч. и для Drupal 5, 6, 7.
Требует установки яндекс-поиска на сайт и добавления сайта в панель Яндекс.Вебмастер. Вроде-бы штука полезная, но я почему-то не могу отправить запрос, модуль говорит: "Яндекс.ПДС: Невозможно отправить пинг. Причина:Сайт не подтвержден в сервисе Яндекс.Вебмастер для указанного имени пользователя". Хотя в сервисе Яндекс.Вебмастер всё давно подтверждено.
Через несколько часов модуль заработал, видать, дошло, поиск Яндекса индексирует сразу новый материал. Чуть переделал CSS и получилось прикольно.
Яндекс выпустил модули "пингеры" для облегчения индексации страниц.
Цитирую Яндекс:
«Вы можете повысить приоритет индексирования некоторых страниц вашего сайта с помощью дополнений для CMS, которые могут отсылать запросы на индексацию автоматически. Дополнение, установленное в CMS, отслеживает изменения на сайте и генерирует запросы на индексацию при создании или изменении документов.»
Подробнее по ссылке + документация
Есть несколько способов создать свои «красивые» страницы для ошибок 403 и 404.
Я расскажу как я это делал через переопределение шаблона.
1. В каталоге текущей темы создаем шаблон для вывода страницы с ошибкой
Содержимое файла самое простое:
<?php /** * @file * $error_code - Error num (403 or 404) * $error_content - HTML error content */ ?> <div class="page clearfix" id="page-<?php print $error_code;?>"> <div class="content-page-<?php print $error_code;?>"> <h2> <?php print l($site_name, '<front>', array('attributes' => array('title' => t('Home')), 'html' => TRUE)); ?> </h2> <h1><?php print $error_code;?></h1> <?php print render($error_content); ?> </div> </div>
2. В файле template.php создаем (или изменяем) две функции
Имя_Вашей_темы_preprocess_html(&$vars) и Имя_Вашей_темы_preprocess_page(&$vars)
Моя тема называется olkit, соответственно и функции будут:
<?php
function olkit_preprocess_html(&$vars) {
$header = drupal_get_http_header();
if (isset($header['status']) && ($header['status']=='403 Forbidden' || $header['status']=='404 Not Found')) {
$vars['attributes_array']['class'][] = 'page-error';
}
}
?>
В данной функции я просто добавляю к тэгу body - дополнительный класс page-error, он мне понадобился для дальнейшего оформления страницы посредством CSS, если вам этого не надо, то можно не переопределять данную функцию.
И наконец основная функция, где мы переопределяем шаблон и заполняем необходимые переменные для обработки в шаблоне.
<?php
function olkit_preprocess_page(&$vars) {
$header = drupal_get_http_header();
if (isset($header['status']) && $header['status']=='403 Forbidden') {
$vars['theme_hook_suggestions'][0] = "page__error";
$vars['error_code'] = 403;
$error_content = "<h6> У вас нет доступа на страницу, которую вы запросили.";
$error_content .= "Возможно, вы ошиблись при наборе адреса, перешли по неверной ссылке или для доступа к данной странице необходимо зарегистрироваться.</h6>";
$error_content .= "<ul><li>проверьте правильность написания адреса</li>";
$error_content .= "<li>воспользуйтесь главной страницей ";
$error_content .= l('Отель «У старого программиста»', '<front>', array('attributes' => array('title' => t('Home')), 'html' => TRUE));
$error_content .= "</li><li>Зарегистрируйтесь на нашем сайте ";
$error_content .= l('Войти', 'user/login', array('attributes' => array('title' => t('Login')), 'html' => TRUE));
$error_content .= " | ";
$error_content .= l('Зарегистрироваться', 'user/register', array('attributes' => array('title' => t('Login')), 'html' => TRUE));
$error_content .= "</li></ul>";
$vars['error_content'] = $error_content;
}
if (isset($header['status']) && $header['status']=='404 Not Found') {
$vars['theme_hook_suggestions'][0] = "page__error";
$vars['error_code'] = 404;
$error_content = "<h6> Страница, которую вы запросили, отсутствует на нашем сайте.";
$error_content .= "Возможно, вы ошиблись при наборе адреса или перешли по неверной ссылке.</h6>";
$error_content .= "<ul><li>проверьте правильность написания адреса</li>";
$error_content .= "<li>воспользуйтесь главной страницей ";
$error_content .= l('Отель «У старого программиста»', '<front>', array('attributes' => array('title' => t('Home')), 'html' => TRUE));
$error_content .= "</li></ul>";
$vars['error_content'] = $error_content;
}
}
?>
«Важный момент:»
строка $vars['theme_hook_suggestions'][0] = "page__error";
определяет какой файл будет применен в качестве шаблона страницы, при этом имя файл шаблона строиться следующим образом, в значении page__error - подчеркивания заменяются на дифисы и добавляется расширение .tpl.php, таким образом для значения page__error файл должен иметь имя page--error.tpl.php
Далее посредством CSS настраиваем внешний вид страниц.
Вот и все, сбрасываем кэш и смотрим что у нас получилось.
Данный материал это репост с моего блога Подключение своих шаблонов для страниц 403 и 404
Ну и небольшой скриншотик
Привет.
Продолжаю свои заметки про работу с поисковиком Solr. В прошлых постах я писал о том, как добавлять в индекс дополнительные поля, как управлять процессом индексации определенного поля и как научить solr искать в этих полях. Сегодня расскажу о том, как можно договориться с solr'ом о том, что индексировать, а что нет. Оговорюсь, что нижеприведенный способ работает адекватно только начиная с версии apachesolr-1.x-beta19, раньше этого не было. Итак, рассказываю.
На самом деле рассказывать то особо и нечего, всё потрясающе просто. Представим, что по определенным признакам мы не хотим индексировать ноду, для этого у apachesolr есть status callback. В моем случае у типа материалов "публикация" есть чекбокс "Индексируемая", по умолчанию отмеченный, но если галочку снимут, то публикация не будет ни индексироваться, ни, само собой, выводиться в результатах поиска. Сделано это следующим образом:
<?php
// Для начала мы должны сообщить модулю apachesolr о использовании кастомного коллбэка. Делается это с помощью
// реализации хука <strong>hook_apachesolr_entity_info_alter()</strong>, описанного в файле apachesolr.api.php.
// Таких коллбэков может быть несколько.
function inti_apachesolr_entity_info_alter(&$entity_info) {
// Способ, как видите, работает не только для нод, а для любых сущностей.
$entity_info['node']['status callback'][] = 'inti_index_node_status_callback';
}
// Эта функция должна возвращать TRUE, если публикация индексируемая, иначе FALSE.
// Коллбэк по умолчанию проверяет, опубликована ли нода. Учитывая, что коллбэков может быть
// несколько, как я написал выше, здесь мне это проверять нет нужды.
function inti_index_node_status_callback($entity_id, $entity_type) {
$node = node_load($entity_id, NULL, TRUE);
$status = TRUE;
if (($node->type == 'publication') && !empty($node->field_do_search)) {
$status = ($node->field_do_search['und'][0]['value']) ? TRUE : FALSE;
}
return $status;
}
?>
Вот и всё. Важное примечание: как я понял, после изменения функции, реализующей hook_apachesolr_entity_info_alter(), нужно очистить кэш.
В следующий раз будет пост (тоже небольшой) о том, как научить Apache Solr искать с использованием wildcard(*). Как ни странно, но по умолчанию, поддержки поиска по частям слов нет.
Ссылки:
Часть 1. О добавлении полей в индекс и фасетах.
Часть 2. О подмене коллбэка для индексации определенного полям и о том, как искать по дополнительным полям.
Приветствую уважаемое сообщество друпалеров, друпалерш, друпалистов и всех сочувствующих!
Как известно, 12 июня в России празднуется День Независимости. А что еще делать в день независимости родной страны, как не уехать из нее в круиз по Балтийскому морю, по столицам Балтики: Санкт-Петербургу, Хельсинки, Таллину, Стокгольму. Можно еще посетить норвежский Осло и знаменитые фиорды, а также Копенгаген...
Как вы, наверное, уже догадались, по нехитрой присказке и тому факту, что эта присказка находится не где-нибудь, а на главной друпал.ру, однажды появилась идея организовать летний круиз по Балтике, с посещением столиц и Друпал-сообществ тех стран и городов, которые будут подвергнуты нашествию славян с медведями, балалайками и сувенирными матрешками (в форме друпал-капли, ага).
Самым естественным форматом для этого, наверное, будет Друпал-кафе, приуроченный местными друпалистами как раз к посещению нами того или иного города. Можно поговорить о том о сем, как другие люди живут, рассказать о себе, послушать, что другие рассказывают, найти партнеров, единомышленников и просто друзей, побродить по городу, обменяться мнениями, а также нефигово отдохнуть и набраться позитивных эмоций на все лето.
Этот пост написан для того, чтобы собрать всех заинтересованных в подобном мероприятии людей, сколотить из них чат в скайпе, совместно выбрать тур, собрать со всех деньги и организованно заказать этот тур. Как только будет ясно, что набирается достаточное количество людей (не меньше четырех; поскольку я еду точно, то нужно еще минимум троих), будет написан пост-объявление на groups.drupal.org с предложением о проведении друпал-кафе в честь русскоязычных гостей и вообще, сделать эту традицию регулярной. Мне кажется, что это будет одним из связующих звеньев между пока что слишком обособленным русскоязычным друпал-сообществом и европейским.
Да что это мы, в самом деле, о сообществе да о сообществе. Основная цель этого мероприятия - хорошо провести время, спланировать свой отпуск с пользой для своего профессионального роста. Отдых среди единомышленников - это отдых вдвойне. Море фана и хорошего настроения. Просто, отдыхая, мы, русские, не забываем о высоких идеалах байтайерт-друпализма и т.д.
Как это все примерно выглядит с организационно-правовой точки зрения? Есть несколько компаний, организующих подобный досуг на Балтийском море и прибрежных городах. Люди покупают билет на круиз, приезжают обычно в Петербург к вечеру дня отплытия, там садятся на паром и плывут в столицы по очереди. Ночью паром плывет, а утром прибывает в порт города. Ночью вы колбаситесь в клубе и барах, а днем с постной миной опохмеляетесь на очередном Друпал-кафе, с ненавистью глядя на кристально трезвых европейцев, не понимающих русскую душу. :)
Маршрут может выглядеть так: Петербург-Хельсинки-Стокгольм-Таллин-Петербург. Возможны вариации: поезд из Москвы до Питера, потом до Хельсинки, оттуда паром до Стокгольма, потом автобус до Осло, автобус до Копенгагена и паром до Питера. В общем, вариантов масса, есть из чего выбрать.
Резюмирую.
1. Вам предлагается взять отпуск на неделю с 11.06 по 17.06 включительно, таким образом получив непрерывный кусок свободного времени с 10.06 по 17.06 включительно (8 календарных дней)
2. В этот период совершить вышеописанный круиз по Балтийскому морю. (не обязательно на все 8 дней)
В случае желания осуществить эти два пункта, прошу сообщить о своем желании мне через сервис личных сообщений на этом сайте, или в скайпе (мой ник там andrey.a.andreev), для добавления вас в группу, собирающуюся таким образом хорошо отдохнуть. В чате скайпа мы уже обсудим все конкретные детали.
Если перед тем, как определиться с желанием и возможностями, у вас есть вопросы, задавайте их в комментариях - я буду периодически обновлять пост, отвечая на вопросы.
Вкратце сориентирую вас по деньгам и немного расскажу о своих впечатлениях.
В 2010 году в майские праздники я с друзьями совершил круиз на пароме по маршруту Питер-Хельсинки-Стокгольм-Таллин-Питер, длительностью 4 дня и 3 ночи. Каюту мы заказывали 4-хместную, самую дешевую, под ватерлинией (иллюминаторов нет), т.к. все свое свободное время (а это вечер и ночь) мы проводили либо в клубе на самой верхней обзорной палубе, танцуя и распивая напитки, либо в своей каюте, отсыпаясь и приводя себя в порядок перед выходом в город. В программу тура входила бесплатная пешая экскурсия по каждому городу, и можно было заказать много других: музей Карлсона в Стокгольме, Церковь в скале в Хельсинки и много-много другого. Понравилось очень, особенно девушки в Таллине. Стокгольм - город-мечта, везде велосипеды. Хельсинки - очень холодный город, достопримечательностей почти нет, а те что есть - построены русскими во времена царизма. Конечно, айтишникам будет этот город интересен из-за личности Линуса Торвальдса. Старый Таллин похож на сказку, удалось даже позвенеть в колокол на старой главной ратуше города. Поездка была весьма позитивной. В мае в Балтийском море довольно холодно и дико ветренно, поэтому, учитывая свой предыдущий опыт, я предлагаю вам поездку в июне.
Мой бюджет на прошлую поездку составил: 244 евро, (в т.ч. тур: 174 евро +70 евро - топливный сбор), или 9800 рублей (курс евро на дату бронирования +2%).
Из каждодневных расходов, нужно на еду (мой расход был заложен 20 евро в день, включая бары, рестораны и Макдональдс), транспорт (обычно универсальный проездной за ~10 евро на любой вид транспорта - метро, автобус, паром, действующий целый день), прочие расходы (сувениры, это прикидывайте сами - от 1 до 100 евро и выше).
Когда я просматривал цены на туры в этот год, 6 дней стоят 320 евро + виза 80 евро (автобусно-паромный тур). Конечно, туры очень разные, и я тут просто привел прикидочную цену для сравнения.
Для оформления документов вам потребуется (список не точный, точный скажет наш оператор. имейте в виду, что этот список ТОЛЬКО для справки):
1. Заграничный паспорт, действительный в течение 3 месяцев со дня возвращения из поездки: в паспорте обязательно должна быть подпись владельца и достаточное количество страниц для визовой наклейки на ребенка, который вписан в паспорт родителя и следует вместе с ним.
2. Полные анкетные данные (заполнить опросник). [прим.: он небольшой одна страница A4, примерно 7 стандартных вопросов]
3. Копия первой страницы заграничного паспорта.
4. Старый заграничный паспорт, если в нем есть Шенгенские визы, выданные за последние 3 года.
5. 2 цветных фотографии 3,5 х 4,5 на белом фоне в анфас без углов и овалов, сделаны не ранее 3 месяцев до подачи документов. Нельзя подавать фотографии, ранее использовавшиеся для получения визы. Не допускаются головные уборы, темные очки и ретушь; голова должна занимать 60-70 % фотографии.
6. Ксерокопия всех страниц внутреннего паспорта (даже чистых!!!) для туристов старше 14 лет.
7. Ксерокопия свидетельства о рождении для туристов младше 14 лет.
8. Справка с места работы с указанием должности, оклада/заработной платы за три последних месяца. Справка предоставляется на фирменном бланке организации, заверенном подписью руководителя/гл. бухгалтера и печатью.
Да-да, для получения Шенгенской визы все это нужно.
Думайте, решайте, планируйте, задавайте вопросы и соглашайтесь!
Attached poll "Нравится идея Балтийских отпускных Drupal-кемпов?".Всем привет. В предыдущем посте я рассказал, как можно "повлиять" на процесс индексации, добавляя дополнительные поля в индекс, и создавать свои фасеты (фильтры) с помощью Facet API. Сегодня я хочу рассказать об альтернативном способе индексирования полей и возможности поиска по дополнительным полям. Дело в том, что Solr не ищет по всем полям, а только по тем, о которых его просят. Итак, поехали.
Представим задачу, когда нам нужно не добавить какое-то поле из связанных материалов, а изменить способ индексации какого-то текущего поля. Например, есть такой модуль Field Collection, позволяющий сделать поле-контейнер, содержащее в себе несколько полей. В моей структуре с помощью него у публикации указывается автор, а к автору - организация, в которой он работает:
В базе данных у меня есть таблица field_data_field_author_org, в которой есть поле value, которое указывает на entity_id поле таблиц field_data_field_author и field_data_field_jobs. Таким образом в индексированном документе публикации я получаю поле im_field_author_org, значение которого мне абсолютно не нужно. Вот для того, чтобы указать, как будет индексироваться поле, мне нужно определить indexing_callback для этого поля в функции, реализующей хук hook_apachesolr_field_mappings(), находящийся в файле apachesolr.api.inc:
<?php
function inti_apachesolr_field_mappings() {
// Функция должна вернуть массив, в котором ключем может быть либо тип поля, либо значение 'per_field'.
// В первом случае мы указываем, как будут индексироваться поля этого типа, во втором - значением будет массив,
// у которого ключем будет имя поля. Настоятельно рекомендую ознакомиться с документацией ко всем хукам, которые
// я указываю в заметках, для этого я пишу, в каких файлах они находятся. Дело в том, что в документации
// это описано довольно подробно, а я лишь хочу описать сам принцип.
$mappings = array();
$mappings['per-field']['field_author_org'] = array(
'indexing_callback' => 'inti_field_author_org_indexing_callback',
// В это поле я хочу записать имена авторов и организаций, поэтому меняю тип с int на text,
// это повлияет на имя поля (см. мой предыдущий пост), которое в данном случае генерируется
// автоматически
'index_type' => 'text',
// Фасеты по этому полю мне не нужны, потому что их я формирую вручную (описано также в предыдщем посте)
'facets' => FALSE,
);
return $mappings;
}
function inti_field_author_org_indexing_callback($entity, $field_name, $index_key, $field_info) {
$fields = array();
// Получаем все значения нашего поля
$field_values = array_map(function($n) { return $n['value']; }, $entity->{$field_name}['und']);
// По этим значениям достаем всех авторов и организации прямо из базы данных
// В момент написания заметки я предположил, что можно было бы воспользоваться функционалом
// самого модуля Field Collection, но это предположение я проверю позже. :)
$select = db_select('node', 'n');
$select->join('field_data_field_author', 'fdfa', 'fdfa.field_author_nid = n.nid');
$select->condition('fdfa.entity_id', $field_values, 'IN');
$select->fields('n', array('title'));
$authors = $select->execute()->fetchCol();
$select = db_select('node', 'n');
$select->join('field_data_field_jobs', 'fdfj', 'fdfj.field_jobs_nid = n.nid');
$select->condition('fdfj.entity_id', $field_values, 'IN');
$select->fields('n', array('title'));
$orgs = $select->execute()->fetchCol();
// Формируем массив с $index_key в кач-ве ключей, и
// именами авторов и названиями всех организаций в кач-ве значений.
$fields[] = array(
'key' => $index_key,
'value' => implode(' ', $authors),
);
$fields[] = array(
'key' => $index_key,
'value' => implode(' ', $orgs),
);
return $fields;
}
?>
Таким образом в результате индексирования поле у меня выглядит следующим образом:
[tm_field_author_org] => Array
(
[0] => Иванов Е. С. Петрова Р. Ш. // Авторы
[1] => Рога и копыта Министерство образования и науки // Организации
)
Теперь мне нужно сообщить Solr'у, что по этому полю тоже необходимо производить поиск. Делается это с помощью реализации хука hook_apachesolr_query_alter(), описанном всё в том же чудесном файле apachesolr.api.php:
<?php
function inti_apachesolr_query_alter($query) {
// Поля, в которых нужно искать, должны быть добавлены в параметр 'qf' поискового запроса.
// Формат параметров - обычный массив, значения которого выглядят как fieldname^boost, т.е. тут же поисковик
// будет уведомлен о приоритетах. В моём случае поле достаточно важное, поэтому приоритет делаю
// высоким. Напомню, что имя поля должно быть указано не то, которое в Drupal'е, а то, которое
// в индексированном документе.
$params = array('tm_field_author_org^25.0');
$query->addParam('qf', $params);
}
?>
Кстати, $query - это интерфейс DrupalSolrQueryInterface, описанный в файле apachesolr.interface.inc, с которым рекомендую ознакомиться, если вы хотите узнать, как еще можно работать с запросом перед его отправкой.
Собственно, вот и всё. В следующем посте расскажу о status_callback и индексировании определенных нод.
Примечание: вышенаписанное актуально для текущих версий модулей apachesolr (7.x-1.0-beta19) и facetapi (7.x-1.0-rc4). Они активно развиваются, поэтому если у вас другая версия и что-то не работает, читайте release notes.
Уважаемые посетители Drupal.ru
Завтра, 11 Апреля 2012 г, запланировано обновление ПО с последующей перезагрузкой сервера, где находится drupal.ru.
Соответственно с 23:00 до 23:59 по Московскому времени возможны перебои в работе сайта.
Просим проявить понимание и терпение.
С Уважением,
Команда IT Patrol inc.
Конференция DrupalConf 2012 состоится 2 июня 2012 года в Москве!
В этот раз мы можем сделать конференцию в 2 потока. У нас уже есть первые заявки на доклады, однако для двух потоков, этого конечно, мало. Заявки на доклады мы планируем принимать до конца майских праздников, однако, если вы хотите сделать доклад, лучше поторопиться, чтобы мы успели забронировать второй зал.
Для того, чтобы стать участником конференции, нужно зарегистрироваться на сайте(или войти на сайт, если у вас уже есть аккаунт), перейти по ссылке Участвовать в шапке, и подтвердить участие в мероприятии. Возможно, если спонсоров будет недостаточно, необходимо будет еще оплатить билет.
Для спонсоров уже сформированы спонсорские пакеты, а владельцы сайтов могут помочь конференции, установив наши баннеры.
До встречи на DrupalConf!
В четверг, 5 апреля, в 19:00, в Харькове пройдет уже четвертое DrupalCafe.
Место проведения - все так же - Выставочный центр «РАДМИР ЭКСПОХОЛЛ», по адресу ул. Академика Павлова 271 (м. Академика Павлова).
Темы докладов:
1. "Архитектура Drupal Commerce. Основы работы с Drupal Commerce" (Александр Мильковский, WDG)
- Архитектура Drupal Commerce.
- Основы работы с Drupal Commerce.
- Краткий обзор полезных модулей.
2. "Drupal 7 Deploy" (Антон Иванов, WDG)
Обзор существующих методов переноса функционала с Dev сайта на Production, а также рассмотрение подхода к разработке который позволяет упростить и автоматизировать Deploy.
3. "Разработка адаптивных шаблонов на базе Omega." (Тарас Омельяненко)
Доклад рассказывает об отличной теме Omega и возможности на полную силу использовать весь ее функционал. Ожидается холивар поклонников темы Fusion.
Участие бесплатное, в программе кофе, чай, блекджек, cookies.
Желательно предварительная регистрация, всем желающим - отпишите в комментарии или в контакты ниже.
https://docs.google.com/spreadsheet/viewform?formkey=dERVTEhMVEdZMVdIVlk...
По всем вопросам можно обращаться:
+38(099)3525316 - Алексей Гайдабура, gaydabura@gmail.com skype: alexey.gaydabura
Спонсор по прежнему - WDG (http://wdg-company.com/)
Друзья, коллеги и мимо проходящие, а также недруги.
Я обратил внимание, что такая очень хорошая инициатива, как ДрупалКафе в Москве в этом году почему-то никак не активизируется. Напомню, что последняя встреча проводилась в декабре 2011, а на дворе уже практически апрель 2012!
На мой взгляд, это недопустимое упущение для русского сообщества в столице России.
Я подумал и решил, что я достаточно смелый и ответственный, чтобы начать организаторскую подготовку к первому ДрупалКафе в 2012 году.
Предлагаю следующее:
- Ориентировочная дата проведения 11 апреля, в вечернее время (ориентируюсь по времени с 19:00 до 23:00).
- Место встречи пока выбирается, но почти уверен, что это будет тихое кафейное заведение, относительно недалеко от центр Москвы (на данный момент обсуждаются варианты недалеко от м. Китай-город и м. Маяковская).
Соответственно от сообщества мне бы хотелось услышать предложения по проведению встречи:
Также хочу уточнить свое видение насчет места и формата проведения мероприятия. Я бы хотел, чтобы это было тихое и светлое место, важно наличие большого телевизора или возможность использования проектора для проведения презентаций. Также считаю немаловажным возможность закусить - в вечернее время любой человек не откажется от чашечки кофе с десертом, а многие я думаю и от легкого ужина. Жду ваших предложений и замечаний!
UPD:
сообщество ДрупалКафе ВКонтакте
страница ДрупалКафе на Facebook
UPD2:
тема на DrupalSN.Ru
В этом году ожидается около 100 участников. Соберутся разработчики из Беларуси, России и Украины. Обязательно будет десант из Германии.
На Drupal Camp Minsk 2012 ожидается некоторый уклон программы в сторону интересов профессиональных веб-разработчиков.
Но начинающие знакомство с Drupal тоже найдут много поучительного.
Конференция также может стать местом общения программистов и руководителей интернет-проектов, которым интересна возможность использования Drupal в своем бизнесе.
Вы так же можете предложить свой доклад, либо сообщить интересующую Вас тему.
В Новосибирске планируется второе DrupalCafe 31 марта.
Ждем всех желающих!
Можете участвовать в активном обсуждении выступлений и предложений дальнейшего развития Drupal-сообщества, разработок и новостей.
Можете выступить сами со своей темой подготовив презентацию.
Предварительные темы докладов:
Иванкин Антон: Вывод изображений в CMS Drupal
Евгений Ильи: Автоматизация контроля соблюдения стандартов кодирования при разработке на Drupal с использованием системы контроля версий git
Виктор Чуханцев: Drupal7+gmap+location+views
Константин Беленький: Open Atrium
Тимофей Прохоров: Мобильные версии сайтов
Константин Осипенко : Использование поискового движка Solr в drupal 7
Предварительная обязательная регистрация
г.Новосибирск, Академгородок, ул. Инженерная 20, Технопарк, конференцзал на 3 этаже
Начало: 31 марта в 12:00
Окончание: 31 марта в 16:00
Помощь в подготовке докладов Роман Чижиков: skype: roman.chizhikov
Презентации докладов с 1-го DrupalCafe можно посмотреть здесь
Организационные вопросы: Павел Прищепа: skype: prischepa.p
info@drupalsib.ru
тел.офиса (383) 233-27-00
Всем привет.
Так сложилось, что передо мной встала задача создать библиографическую систему для хранения научных публикаций в большом количестве. Ну и как в любой нормальной библиографической системе, мне нужен поиск. На момент начала работы я уже был знаком с модулями Apachesolr search integration и Facet API, работающими в связке, и у которых довольно много возможностей из коробки, а помимо них есть ведь и API. Так вот некоторые мои задачи из коробки не решались, пришлось пообщаться и с разработчиками, и поковыряться в коде, поэтому я таки решил написать о решении некоторых задачек здесь. Возможно, кому-то будет полезно, возможно кто-то предложит, как сделать лучше.
Итак, поехали. Расписывать модули и что они делают, я не буду, это неинтересно, можно почитать на drupal.org и в интернете, благо, такой информации достаточно. В этом посте я хочу рассказать о том, как можно создавать свои собственные фильтры (их еще называет фасетами).
Дело в том, что в моём проекте достаточно непростая структура. Так, например, у меня есть тип материала "Публикация", у которого есть поле - ссылка на материал типа "Издание". В свою очередь, у издания есть поле - ссылка на материал "Издательство". Таким образом, когда я ищу публикации, в списке доступных фильтров я вижу "Издания", но, что если я хочу фильтровать результаты поиска по издательствам, когда они привязаны к публикациям не напрямую?
Один из предложенных вариантов решения этой задачки было ручное индексирование публикаций. Добавив в индексированную публикацию поле издательства мы легко получим нужный фильтр. Добавить поле можно с помощью реализации хука hook_apachesolr_index_document_build() (если вы такого хука не нашли, значит у вас старая версия модуля apachesolr, где он называется hook_apachesolr_update_index()), описанного в файле apachesolr.api.php:
<?php
function inti_apachesolr_index_document_build($document, $node, $namespace) {
if ($node->type == 'publication') {
if (!empty($node->field_edition)) {
// Примечание: $node->field_edition - это ассоциативный массив, в котором ключами являются языки, это важно понимать при индексировании.
// В данном случае у меня материалы не привязаны к языку, поэтому ключ массива я захардкодил.
foreach ($node->field_edition['und'] as $edition) {
if (!empty($edition['node']->field_publishing_house)) {
foreach ($edition['node']->field_publishing_house['und'] as $pubhouse) {
// Ну а таким образом я добавляю новое поле в наш документ. Здесь хочу добавить два примечания.
// Первое: В качестве значения не надо пихать весь термин, или всю ноду, а достаточно проиндексировать идентификатор.
// Второе: У Apachesolr есть правила именования поля. Название всегда должно быть формата xy_fieldname, где
// x - тип поля (s - строка, t - текст, i - тип long, а f - float), а y - количество значений (s - одно, m - несколько).
// В моем примере в поле хранится идентификатор, а издательство у издания может быть только одно.
// fieldname может быть любым, но для себя я решил, что разделяю его на две части, где первая хранит информацию о том, чье это поле,
// а вторая - о том, что это поле содержит. pub - публикация, pubhouse - издательство.
$document->addField('is_pub_pubhouse', $pubhouse['nid']);
}
}
}
}
}
}
?>
Таким образом в самом друпале у нас публикация не хранит информацию о своём издательстве, а в индексе хранит. И помимо этого, может хранить любую другую информацию, какую разработчик пожелает туда "запихнуть".
Но этого недостаточно. Теперь мы должны рассказать модулю Facet API, что мы хотим по этому полю получить фильтр. Это, в свою очередь, решается с помощью реализации хука hook_facetapi_facet_info(), описанного в файле facetapi.api.php:
<?php
function mymodule_facetapi_facet_info($searcher_info) {
// Данная функция должна возвращать ассоциативный массив с описаниями полей, где
// ключом является само название поля.
$facets = array();
$facets['is_pub_pubhouse'] = array(
// Название фильтра на странице настройки.
// Учитывая, что каждый фильтр отображается в блоке, а заголовок блока я всегда успею переопределить,
// метку я тоже решил делать понятной
'label' => t('Publication->Pubhouse'),
'description' => t('Pubhouse facet for publications'),
// Здесь я должен указать название коллбэка, который будет вместо идентификаторов подставлять нормальные
// значения. Для полей - ссылок на таксономию рекомендую использовать уже готовый коллбэк
// facetapi_map_taxonomy_terms, для ссылок на ноды я создал свой коллбэк, для полей со списком значений
// я создавал отдельные коллбэки, хотя возможно, можно это сделать изящнее.
// Помимо этого, здесь можно указать параметры фильтра такие, как, например, древовидность (hierarchy_callback).
// Подробнее можно посмотреть в вышеуказанном файле facetapi.api.php в коде описания хука.
'map callback' => 'mymodule_map_node_references',
);
}
function mymodule_map_node_references(array $values) {
// Здесь все очень просто, коллбэк возвращает ассоциативный массив, где ключ массива - это значение, хранимое в поле,
// а значение в массиве - это то, что должен увидеть пользователь.
$map = array();
if ($values) {
$map = db_select('node', 'n')->fields('n', array('nid', 'title'))->condition('n.nid', $values, 'IN')->execute()->fetchAllKeyed();
}
return $map;
}
?>
Вот, собственно, и всё. Теперь после включения модуля и переиндексации содержимого на сайте (еще может потребоваться очистка кэша) на странице фильтров я могу увидеть свой фильтр, включить его, настроить и, собственно, пользоваться.
В следующем посте я хочу рассказать, как сделать свой собственный виджет для отображения фильтра, и для чего его вообще может понадобиться делать.
Примечание: вышенаписанное актуально для текущих версий модулей apachesolr (7.x-1.0-beta16) и facetapi (7.x-1.0-rc4). Они активно развиваются, поэтому если у вас другая версия и что-то не работает, читайте release notes.
OG Features - модуль позволяющий администратору сайта определять, какой функционал в группе может включаться и отключаться владельцем группы.
Например, это могут быть произвоизвольные типы контента, вьюхи, панели. Яркий пример использования этого модуля, это сборка Drupal Commons, где через og_features сделаны такие фичи для групп как:
Сам процесс создания фичи для OG Features нетривиален.
Для этого вам нужно создать свой модуль, где нужно реализовать хук hook_og_features_registry().
Например, у нас модуль называется modulename и мы хотим определить фичу my_feature, код будет следующий, код взяд из модуля, комментарии оставлены оригинальные и строкой ниже добавлены мои:
function modulename_og_features_registry() {
$registry = array();
// Feature: my_feature.
// Создание объекта фичи.
$feature = new stdClass;
// The feature id
//Указываем id фичи, оно должно быть уникальным в пределах сайта
$feature->id = 'my_feature';
// The name that will show up on the feature toggle form
//Название фичи, которое будет показываться в группе на странице управления фичами
$feature->name = t('Blog');
// The description that will show up on the feature toggle form
//Описание, показываемое на странице управления фичами
$feature->description = t('Provide a simple blog for your group');
// The components of the feature that will be enabled/disabled
//Компоненты которые включает фича
$feature->components = array(
'views' => array(
'og_tab_blogs',
),
'node' => array(
'blog',
),
'context' => array(
'group_blogs',
),
'path' => array(
'node/%node/aggregator',
),
'pane' => array(
'og_content_tracker-panel_pane_1',
),
'og link' => array(
'og_invite', // The key of the link in the group details block
),
);
// It's recommended that you key the feature with the name of the
// module/feature that is supplying this, so that any custom page
// callbacks provided by this module/feature become disabled within
// the group
//помещаем фичу в "контейнер", это позволит нам в модуле определить несколько фич, если требуется
$registry[$feature->id] = $feature;
// Feature: my_second_feature
//объявляем вторую фичу
$feature = new stdClass;
// You can continue to add as many as you'd like
//в дальнейшем процесс никак не отличается от первой фичи, в конце делаем так же $registry[$feature->id] = $feature;
return $registry;
}
С 19-го по 21-е апреля в Харькове чистый кодинг без границ в команде профессионалов под руководством ведущих украинских контрибьюторов.
Принять участие в мероприятие абсолютно БЕСПЛАТНО может любой желающий, но количество мест ограничено. Спешите!
Подробности на сайте мероприятия - http://drupalcodesprint.com/
Контакты организаторов:
Тел.: +38 (067) 5777-369
E-mail: info@drupalcodesprint.com
На сайте опубликованы темы проектов для голосования и обсуждения.
Тимлиды проектов код-спринта: