Сохранение файлов, загруженных с помощью One Click Upload, в File/Image field
Одной из причин, по которой некоторые обходили стороной модуль One Click Upload, это загрузка файлов "в никуда". Т.е. загруженные файлы никак не связанны с тем содержимым, в котором они выводятся и нет способа автоматически удалять эти файлы при удалении содержимого.
С помощью последней dev версии модуля и небольшого количества кода, можно сохранять файлы в любое file или image поле.
Пример сохранения картинок в поле field_inline_images для нод и комментариев:
/**
* Implements hook_ocupload_files_saved().
*/
function MODULENAME_ocupload_saved_data_alter(&$files, &$form, &$form_state) {
if (
isset($form['#entity_type']) &&
in_array($form['#entity_type'], array('node', 'comment')) &&
isset($form_state['values']['field_inline_images'])
) {
foreach ($files as $file) {
$form_state['values']['field_inline_images']['und'][] = array(
'fid' => $file->fid,
'_weight' => 100,
);
}
}
}
Замечание: опция Delete unused files в настройках модуля должна быть включена.
Написанное актуально для
One Click Upload 7.x-1.x-dev
Собственное событие для Rules 2
Создание своего event-a для Rules состоит из двух шагов — реализация hook_rules_event_info() и вызов rules_invoke_event().
Пример события, которое возникает после смены имени пользователя:
/**
* Implements hook_rules_event_info().
*/
function modulename_rules_event_info() {
$items = array(
'user_name_changed' => array(
'label' => t('After changing user name'),
'group' => t('User'),
'variables' => array(
'user' => array(
'type' => 'user',
'label' => t('user'),
),
),
),
);
return $items;
}
/**
* Implements hook_entity_update().
*/
function modulename_entity_update($entity, $type) {
if ($type == 'user' && $entity->name != $entity->original->name) {
rules_invoke_event('user_name_changed', $entity);
}
}
Написанное актуально для
Rules 2
Очистить get форму от лишних параметров (form_build_id, form_token, form_id, op)
Если нужно отправить форму методом get на внешний адрес и при этом не хочется светить form_build_id, form_token, form_id и op:
/**
* Form
*/
function mymodule_myform($form, &$form_state) {
$form['#action'] = 'http://example.com/path';
$form['#method'] = 'GET';
$form['#pre_render'][] = 'mymodule_myform_pre_render';
...
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#name' => '',
);
return $form;
}
/**
* Form pre render callback.
*/
function mymodule_myform_pre_render($form) {
unset($form['form_token']);
unset($form['form_build_id']);
unset($form['form_id']);
return $form;
}
Написанное актуально для
Drupal 7
Вывести регион в node.tpl.php
Пример вывода региона before_comments перед комментариями:
1. Добавить в THEMENAME.info:
regions[before_comments] = Before comments
2. Добавить в template.php:
/**
* Preprocess function for node.tpl.php.
*/
function THEMENAME_preprocess_node(&$vars) {
$vars['region']['before_comments'] = block_get_blocks_by_region('before_comments');
}
3. В node.tpl.php, перед выводом $content['comments'] добавить:
<?php echo render($region['before_comments']); ?>
4. Сбросить кэш.
Написанное актуально для
Drupal 7
Узнать следующий/предыдущий термин
Задача — зная tid термина, узнать следующий и предыдущий термин.
Решение:
/**
* Return prev/next term.
*/
function helper_get_sibling_term($tid, $type) {
$term = taxonomy_term_load($tid);
if ($type == 'next') {
$operator = '>';
$direction = 'ASC';
}
else {
$operator = '<';
$direction = 'DESC';
}
return db_select('taxonomy_term_data', 'td')
->fields('td', array('tid', 'name'))
->condition('td.vid', $term->vid)
->where(
"td.weight $operator :weight OR (td.weight = :weight AND td.name $operator :name)",
array(':weight' => $term->weight, ':name' => $term->name)
)
->orderBy('td.weight', $direction)
->orderBy('td.name', $direction)
->range(0, 1)
->execute()
->fetchObject();
}
Использование:
$prev_term = helper_get_sibling_term(123, 'prev');
$next_term = helper_get_sibling_term(123, 'next');
Написанное актуально для
Drupal 7
Показать процесс загрузки ajax таба в Quicktabs 7.x-3.x
В версии же для Drupal 7 процесс загрузки показывается с помощью throbber-а возле активного таба, что по моему ужасно (контент при этом просто пропадает, а табы скачут)
Делаем по-старому:
1. Добавляем в js файл темы:
(function ($) {
Drupal.behaviors.THEMENAME= {
attach: function (context, settings) {
$('.quicktabs-tabs a:not(.quicktabs-loaded)', context).click(function() {
if ($(this).hasClass('progress-disabled')) {
$(this).closest('.quicktabs-wrapper').addClass('quicktabs-loading');
}
});
if ($(context).hasClass('quicktabs-tabpage')) {
$(context).closest('.quicktabs-wrapper').removeClass('quicktabs-loading');
}
}
};
})(jQuery);
2. Добавляем в css файл темы:
.quicktabs-tabs .ajax-progress {
display: none;
}
.quicktabs-loading .quicktabs_main {
height: 30px;
margin-top: 20px;
background: url(/misc/progress.gif);
}
Написанное актуально для
Quicktabs 7.x-3.x
Программно вывести свой контент в вкладках Quicktabs
Пример вывода двух вкладок Quicktabs с произвольным контентом:
Drupal 7:
$custom_tabs = array(
array('title' => 'Tab 1', 'contents' => 'Content for tab 1'),
array('title' => 'Tab 2', 'contents' => 'Content for tab 2'),
);
echo drupal_render(quicktabs_build_quicktabs('my_custom_tabs', array(), $custom_tabs));
Drupal 6:
$tabs = array(
'tab_1' => array('type' => 'freetext', 'title' => 'Tab 1', 'text' => 'Content for tab 1'),
'tab_2' => array('type' => 'freetext', 'title' => 'Tab 2', 'text' => 'Content for tab 2'),
);
echo theme('quicktabs', array(
'qtid' => 'my_custom_tabs',
'tabs' => $tabs,
'style' => variable_get('quicktabs_tabstyle', 'nostyle'),
'ajax' => FALSE,
));
Написанное актуально для
Quicktabs 3.x
Уникальные классы пунктов меню
У системных меню, выведенных в page.tpl.php с помощью theme_links() есть приятная особенность — все пункты обладают уникальным css классом на основе их идентификатора. В меню же, выводимых модулем Block, таких классов увы нет. Решаем проблему:
// template.php
/**
* Implements hook_preprocess_menu_link().
*/
function THEMENAME_preprocess_menu_link(&$vars) {
$vars['element']['#attributes']['class'][] = 'menu-item-' . $vars['element']['#original_link']['mlid'];
}
Написанное актуально для
Drupal 7
Программно получить список товаров в корзине Drupal Commerce
Пример получения идентификаторов товаров в корзине текущего пользователя:
$product_ids = array();
if (($order_id = commerce_cart_order_id($GLOBALS['user']->uid)) != FALSE) {
$order = entity_metadata_wrapper('commerce_order', $order_id);
foreach ($order->commerce_line_items as $line_item) {
$product_ids[] = $line_item->commerce_product->product_id->value();
}
}
Написанное актуально для
Drupal Commerce 1
Вывести в блоке погоду в Москве на основе данных яндекса
Пример модуля для вывода в блоке текущей погоды в Москве:
Пример блока
/**
* Implements hook_block_info().
*/
function weather_block_info() {
return array(
'weather' => array(
'info' => 'Погода в Москве',
'cache' => DRUPAL_NO_CACHE,
),
);
}
/**
* Implements hook_block_view().
*/
function weather_block_view($delta = '') {
$block = array();
if ($delta == 'weather') {
$weather = weather_get_weather();
$block['subject'] = 'Погода в Москве';
$block['content'] = '
<img src="http://img.yandex.net/i/wiz' . $weather['image'] . '.png" alt="' . $weather['type'] . '" />
' . ($weather['temperature'] > 0 ? '+' . $weather['temperature'] : $weather['temperature']) . '
';
}
return $block;
}
/**
* Return weather.
*/
function weather_get_weather($ignore_cache = FALSE) {
if (!$ignore_cache && ($cache = cache_get('weather'))) {
$weather = $cache->data;
}
else {
$xml = simplexml_load_file('http://export.yandex.ru/weather-ng/forecasts/27530.xml');
$weather = array(
'temperature' => (string)$xml->fact->temperature,
'image' => (string)$xml->fact->image,
'type' => (string)$xml->fact->weather_type,
);
cache_set('weather', $weather);
}
return $weather;
}
/**
* Implements hook_cron().
*/
function weather_cron() {
if (REQUEST_TIME - variable_get('cron_last') > 60*60) {
weather_get_weather(TRUE);
}
}
Информация о погоде обновляться каждый час при ближайшем запуске крона.
Чтобы вывести погоду для другого города, достаточно в адресе xml-ки заменить 27530 на id города.
Написанное актуально для
Drupal 7
Программно добавить поле в представление
Программное добавление полей в представление articles с дисплеем page:
/**
* Implements hook_views_pre_view().
*/
function MODULENAME_views_pre_view(&$view) {
if ($view->name == 'articles' && $view->current_display == 'page') {
// Добавление заголовка материала
$view->add_item($view->current_display, 'field', 'node', 'title', array(
'label' => 'Title',
), 'node_title');
// Добавление поля типа Custom text
$view->add_item($view->current_display, 'field', 'views', 'nothing', array(
'label' => 'My custom field',
'alter' => array('text' => 'My custom field text'),
'element_class' => 'my-custom-field',
'element_default_classes' => 0,
), 'my_custom_field');
}
}
Написанное актуально для
Views 3
Удаляем друпаловский ресайзер textarea (grippie)
Переопределённый шаблон вывода textarea из которого удалены все упоминания grippie:
// template.php
/**
* Override theme_textarea().
*/
function THEMENAME_textarea($vars) {
$element = $vars['element'];
element_set_attributes($element, array('id', 'name', 'cols', 'rows'));
_form_set_class($element, array('form-textarea'));
return '<textarea' . drupal_attributes($element['#attributes']) . '>' . check_plain($element['#value']) . '</textarea>';
}
Используется в моей базовой теме.
Написанное актуально для
Drupal 7
Показывать блок только на страницах терминов определённого словаря
Пример вывода блока только на страницах термина словаря tags:
<?php
if (
arg(0) == 'taxonomy' &&
arg(1) == 'term' &&
($term = taxonomy_term_load(arg(2))) &&
$term->vocabulary_machine_name == 'tags'
) {
return TRUE;
}
?>
Код прописывается в настройках видимости блока, с включённой опцией Pages on which this PHP code returns TRUE (experts only):
Модуль для вывода блока только на странице определённых терминов — Block Visibility by Term.
Написанное актуально для
Drupal 7
AJAX кнопка "Добавить в корзину" в Drupal Commerce
Код, позволяющий добавлять товары в корзину с помощью AJAX:
/**
* Implements hook_form_FORM_ID_alter(): commerce_cart_add_to_cart_form
*/
function modulename_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state) {
$form['submit']['#ajax'] = array('callback' => 'modulename_add_to_cart_ajax_callback');
$form['#submit'][] = 'modulename_add_to_cart_form_submit';
}
/**
* "Add to cart" button ajax callback.
*/
function modulename_add_to_cart_ajax_callback($form, &$form_state) {
drupal_get_messages();
$cart_block = module_invoke('commerce_cart', 'block_view', 'cart');
return array(
'#type' => 'ajax',
'#commands' => array(
ajax_command_html('#block-commerce-cart-cart .content', render($cart_block['content'])),
),
);
}
/**
* "Add to cart" button submit callback.
*/
function modulename_add_to_cart_form_submit($form, &$form_state){
$form_state['rebuild'] = TRUE;
}
Код может конфликтовать с dev версией Commerce Cart Ajax, потому что модуль достаточно кривой.
Написанное актуально для
Drupal Commerce 1.x
Реализация AJAX кнопки "Add more" с помощью progressive enhancement
Пример реализации формы с кнопкой Add more, добавляющей бесконечное количество полей Name:
Создаём форму, которая будет работать с выключенным Javascript:
/**
* Form builder.
*/
function example_add_more_form($form, &$form_state) {
$form['names'] = array(
'#tree' => TRUE,
);
// See example_add_more_form_add().
if (empty($form_state['name_count'])) {
$form_state['name_count'] = 1;
}
for ($i = 0; $i < $form_state['name_count']; $i++) {
$form['names'][$i]['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
);
}
$form['add_more'] = array(
'#type' => 'submit',
'#value' => t('Add more'),
'#submit' => array('example_add_more_form_add'),
);
return $form;
}
/**
* "Add more" button submit callback.
*/
function example_add_more_form_add($form, &$form_state) {
$form_state['name_count']++;
$form_state['rebuild'] = TRUE;
}
Добавляем AJAX функционал:
/**
* Form builder.
*/
function example_add_more_form($form, &$form_state) {
$form['names'] = array(
'#tree' => TRUE,
'#prefix' => '<div id="names-wrapper">', // <-- New
'#suffix' => '</div>', // <-- New
);
// See example_add_more_form_add().
if (empty($form_state['name_count'])) {
$form_state['name_count'] = 1;
}
for ($i = 0; $i < $form_state['name_count']; $i++) {
$form['names'][$i]['name'] = array(
'#type' => 'textfield',
'#title' => t('Name'),
);
}
$form['add_more'] = array(
'#type' => 'submit',
'#value' => t('Add more'),
'#submit' => array('example_add_more_form_add'),
'#ajax' => array( // <-- New
'wrapper' => 'names-wrapper',
'callback' => 'example_add_more_form_update',
),
);
return $form;
}
/**
* "Add more" button submit callback.
*/
function example_add_more_form_add($form, &$form_state) {
$form_state['name_count']++;
$form_state['rebuild'] = TRUE;
}
/**
* "Add more" button ajax callback.
*/
function example_add_more_form_update($form, $form_state) { // <-- New
return $form['names'];
}
Написанное актуально для
Drupal 7