xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Сложные условия видимости блока / Программно ограничить видимость блока

Опубликовано в

Дефолтных условий видимости блока часто не хватает. PHP filter выручает, но это не друпалвэй. Решение — hook_block_list_alter().

Пример вывода блока только для пользователей зарегистрированных меньше 5 минут назад:

/**
 * Implements hook_block_list_alter().
 */
function MODULENAME_block_list_alter(&$blocks) {
  $bid = 123;
 
  // Минимально-необходимые проверки
  if (!isset($blocks[$bid]) || !isset($blocks[$bid]->theme) || !isset($blocks[$bid]->status) || $blocks[$bid]->theme != $GLOBALS['theme_key'] || $blocks[$bid]->status != 1) {
    return;
  }
 
  // Наше условие видимости
  $user = $GLOBALS['user'];
  if (!($user->uid && REQUEST_TIME - $user->created < 60*5)) {
    unset($blocks[$bid]); // Удаляем блок из списка
  }
}

123 — это bid блока. Посмотреть можно в таблице block или в dsm($blocks);.

Если блоков будет много, то можно пойти дальше и вынести проверку видимости в callback:

/**
 * Implements hook_block_list_alter().
 */
function MODULENAME_block_list_alter(&$blocks) {
  foreach ($blocks as $key => $block) {
    if (!isset($block->theme) || !isset($block->status) || $block->theme != $GLOBALS['theme_key'] || $block->status != 1) {
      continue;
    }
 
    $function = 'MODULENAME_block_visible_' . $block->module . '_' . str_replace('-', '_', $block->delta);
    if (function_exists($function) && !$function($block)) {
      unset($blocks[$key]);
    }
  }
}

Использовать так:

/**
 * Block visibility callback.
 */
function MODULENAME_block_visible_MODULE_DELTA($block) {
  $user = $GLOBALS['user'];
  return $user->uid && REQUEST_TIME - $user->created < 60*5;
}

MODULE — имя модуля в котором создан блок
DELTA — делта блока

Как отметили в комментариях, на основе этого способа даже есть модуль — Extended block visibility.

Написанное актуально для Drupal 7
Похожие записи

Комментарии RSS

здорово, буду знать

Самый Drupalway - это Context :)

"PHP filter выручает, но это не друпалвэй. "

А почему это не друпалвэй? Что вообще считается друпалвэй и не друпалвэй?
Разработкой сайтов на друпал занимаюсь не так давно и в таких тонкостях еще не очень разбираюсь. Но если уж функционал php фильтров заложен по дефолту, то почему же это не друпалвэй?

кода в базе быть не должно

Почему? Что криминального в коде в базе?

1. тяжело писать
2. тяжело отлаживать
3. тяжело искать
4. тяжело деплоить
5. невозможно использовать систему контроля версий
6. выполняется дольше
7. проблемы с безопасностью
8. проблемы с кэшированием

ок... А если например я создаю некий блок программно (просто пишу файл php, в котором обращаюсь к БД, делаю нужные выборки и прочее), то как лучше всего подключить этот блок на нужные страницы? На данный момент я использую два варианта: 1. php-фильтр в блоках, где просто инклужу свой файл. 2. в файлах .page.tpl где задаю php-условие для показа блока.
Первый вараинт - не "друпалвэй", по описанным вами причинам. Второй - "говнокод", потому что мешает php-код и верстку в шаблоне.
Наверное, существуют куда как более оптимальные варианты?

Как программно ограничить видимость блока написано в посте выше

Это если блок - именно блок в структуре друпала. То есть, есть в списке блоков. А если это просто php-файл?

не понимаю вопроса

ну вот вы пишите:
if (!isset($blocks[$bid])....
где $bid - id блока.

То есть этот блок был создан в "структура - блоки". Так? Имеет свой id и к нему можно добраться через массив $blocks.

а я говорю, не о блоке, а о просто php-файле, результат работы которого мне нужно подключать на моих страницах по аналогии с тем, как мы подключаем блоки - на этой странице виден, а на этой нет. Вопрос в том, как в друпале лучше подключать подобные файлы? Можно же создать блок ("структура - блоки"), включить PHP и написать include myfile.php, после чего указать на каких страницах этот блок будет отображаться, использую стандартный интерфейс блоков. А можно вообще с блоками не связываться, а указать в файле node.tpl.php
if (node - > type == 'news')  include myfile.php;
Но оба варианта, как я понимаю, не фонтан. так как же правильнее поступать в таких случаях?

создайте блок самостоятельно http://xandeadx.ru/blog/drupal/255

о, спасибо! :)

А есть в друпале функция программной реализации видимости блока по пути?
Например, как программно сказать, что блок должен отображаться только на страницах blog/* к примеру

Немного не то. Мне необходимо чтобы блок отображался при наличии сессии $_SESSION['city'] и скажем на всех страницах blog/*
Вот как программно реализовать проверку пути по маске blog/*

https://api.drupal.org/api/drupal/includes!path.inc/function/drupal_match_path/7

Крут, именно то что нужна.
Большое спасибо, полезное дело делаете!

Здравствуйте, а подскажите пожалуйста как прописать, чтобы на главной блок не выводился для администратора.
Можно запретить для администратора, но тогда не будет исполнятся условие выводить только на главной, и блок выводится просто везде.

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании