Курим систему меню Drupal

Аватар пользователя orangeudav orangeudav 30 ноября 2010 в 17:24

Рассмотрим кусок меню на обычном сайте.

Пока все стандартно. Теперь мы хотим, чтобы когда пользователь нажимает на меню Компания ему открывалась страница О компании.

Неправильное решение

Можно попытаться присвоить пункту Компания тот же самый адрес node/45. Пользователь делает клик на Компания .. И тут мы обнаруживаем интересную особенность Друпала. Из двух пунктов меню с одинаковыми адресами активным (class="active") Друпал сделает только один - первый по списку. Кроме того, если вы играетесь с модулем Custom Breadcrumbs - вы получите неверные хлебные крошки.
Дальше у нас есть выбор - сдаться и сделать для пункта меню Компания отдельную нормальную страницу. Либо включить хитрость и сделать страницу-редиректор которая бы перекидывала пользователя с Компания на О компании.

Как не надо делать

Начитавшись Drupal API у вас может возникнуть "гениальная" идея. Создаем новый тип материала, например, fake_page, делаем новую ноду этого типа и в ней пишем


  drupal_goto('node/45');
?>

Плюсов у этого решения нет, одни недостатки:

  • Внезапно отваливается индексация поиска. И вообще весь крон. В watchdog вы увидите сообщение "Cron run exceeded the time limit and was aborted.", хотя сам крон отрабатывается мгновенно. Через некоторое время (большое? ;) вы обнаружите, что крон умирает именно в модуле search. И именно на ноде-редиректоре.
  • Человек, пришедший после вас, при попытка посмотреть содержимое fake_page будет попадать в другое место и долго удивляться что за фигня.

Правильное решение

Существует прекрасный модуль Path redirect, который в явном виде позволяет задать переадресацию с одного адреса на другой. А с помощью расово верного патча он позволяет делать переадресацию с уже существующего пути в любое другое место. Почему с уже существующего? Потому что Друпал не позволит создать пункт меню Компания с пустым адресом.
Теперь о том, где взять "уже существующий путь". По прежнему мы можем создавать пустые ноды типа fake_page, делать им красивые алиасы и адреса этих нод указывать в качестве путей для меню. Но мне этот подход не нравится тем, что эти пустые ноды будут болтаться в списке контента.
Другой подход - следуя модному в стране тренду, сделать наномодуль ;). Который только тем и будет заниматься, что объявлять нужный нам адрес существующим. Далее пример такого модуля:

nanofake.info

name = Nanofake
description = Emulates fake addresses
core = 6.x

nanofake.module

function nanofake_menu() {
  $items['fake1'] = array(
    'page callback' => 'nanofake_none',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
 
  return $items;
}

function nanofake_none() {
  return '';
}

Теперь для пункта меню мы можем указать fake1 в качестве path, а в path redirector сделать перенаправление с fake1 на node/45.
Все это конечно только мой опыт (вполне возможно это все велосипед) и если у кого-то есть опыт более позитивный - прошу в комментарии.

ВложениеРазмер
Иконка изображения illustrate-1.png6.44 КБ
Иконка пакета nanofake.zip592 байта
0 Thanks

Комментарии

Аватар пользователя natbampo natbampo 1 декабря 2010 в 8:41

В ядре такое делается так(пример из модуля block):
<?php
function block_menu() {
$items['admin/build/block'] = array(
'title' => 'Blocks',
'description' => 'Configure what block content appears in your site\'s sidebars and other regions.',
'page callback' => 'block_admin_display',
'access arguments' => array('administer blocks'),
'file' => 'block.admin.inc',
);
$items['admin/build/block/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);

?>
, т.е. используется тип меню MENU_DEFAULT_LOCAL_TASK - вкладки

Аватар пользователя seaji seaji 1 декабря 2010 в 12:43

Я использовал ссылку на одну и ту же страницу у пункта меню и его подпункта. Они оба получили класс active. Drupal 6.16
Не пойму в чем может быть "неправильность" такого подхода.

Редиректы, кстати, то-же не есть гуд.

Если уж кровь из носа нужна другая страница с тем же содержанием, то я бы использовал:

<?php
$node = node_load($nid);
print node_view($node, FALSE, TRUE);
?>

На мой взгляд это как то лучше чем городить огород из псевдо-модулей и псевдо-алиасов.

Аватар пользователя Razunter Razunter 2 декабря 2010 в 8:29
seaji wrote:

Я использовал ссылку на одну и ту же страницу у пункта меню и его подпункта. Они оба получили класс active. Drupal 6.16
Не пойму в чем может быть "неправильность" такого подхода.

Редиректы, кстати, то-же не есть гуд.

Если уж кровь из носа нужна другая страница с тем же содержанием, то я бы использовал:

<?php
$node = node_load($nid);
print node_view($node, FALSE, TRUE);
?>

На мой взгляд это как то лучше чем городить огород из псевдо-модулей и псевдо-алиасов.

Плохое решение, поисковикам не понравится.

ИМХО, лучшее решение будет special_menu_items и через него создать пункт без ссылки.

Аватар пользователя Mirocow Mirocow 2 декабря 2010 в 7:42
"natbampo" wrote:

Кстати это наилучший метод. Я использую преимущественно его.

Аватар пользователя seaji seaji 2 декабря 2010 в 13:33
Loac wrote:

А если так?


<?php
  header
('Location: ' url('node/60'));
?>

Я сомневаюсь что так пойдет.
Скорее всего Вы получите сообщение, что хедеры уже отправлены.
Просто если хоть один байт контента уже ушел, то хедеры отправлять низя.

Аватар пользователя Loac Loac 2 декабря 2010 в 14:10
seaji wrote:

Скорее всего Вы получите сообщение, что хедеры уже отправлены.
Просто если хоть один байт контента уже ушел, то хедеры отправлять низя.

Я знаю, но работает :\

Аватар пользователя natbampo natbampo 2 декабря 2010 в 14:54
"Loac" wrote:

а drupal_goto думаешь чем занимается? (У ТС в разделе "Как не надо делать")

Аватар пользователя rsashka rsashka 2 декабря 2010 в 20:22
"Razunter" wrote:

ИМХО, лучшее решение будет special_menu_items и через него создать пункт без ссылки.

+1
Сделано специально для этого